add xvid/flv formats, add motion plugin varients + save file, fix build bug
authorGood Guy <good1.2guy@gmail.com>
Mon, 21 Nov 2016 03:46:36 +0000 (20:46 -0700)
committerGood Guy <good1.2guy@gmail.com>
Mon, 21 Nov 2016 03:46:36 +0000 (20:46 -0700)
77 files changed:
cinelerra-5.1/cinelerra/ffmpeg.C
cinelerra-5.1/ffmpeg/audio/f4v.dfl [new file with mode: 0644]
cinelerra-5.1/ffmpeg/audio/flv.dfl [new file with mode: 0644]
cinelerra-5.1/ffmpeg/audio/mp3.f4v [new file with mode: 0644]
cinelerra-5.1/ffmpeg/audio/mp3.flv [new file with mode: 0644]
cinelerra-5.1/ffmpeg/encode.opts
cinelerra-5.1/ffmpeg/flv.dfl [new file with mode: 0644]
cinelerra-5.1/ffmpeg/video/avi.xvid [new file with mode: 0644]
cinelerra-5.1/ffmpeg/video/f4v.dfl [new file with mode: 0644]
cinelerra-5.1/ffmpeg/video/flv.dfl [new file with mode: 0644]
cinelerra-5.1/ffmpeg/video/flv.flv [new file with mode: 0644]
cinelerra-5.1/ffmpeg/video/h264.f4v [new file with mode: 0644]
cinelerra-5.1/ffmpeg/video/xvid.dfl [new file with mode: 0644]
cinelerra-5.1/plugin_defs
cinelerra-5.1/plugins/Makefile
cinelerra-5.1/plugins/interpolatevideo/Makefile
cinelerra-5.1/plugins/interpolatevideo/interpolatevideo.C
cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.C [new symlink]
cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.h [new symlink]
cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.inc [new symlink]
cinelerra-5.1/plugins/interpolatevideo/motionscan.C [deleted symlink]
cinelerra-5.1/plugins/interpolatevideo/motionscan.h [deleted symlink]
cinelerra-5.1/plugins/interpolatevideo/motionscan.inc [deleted symlink]
cinelerra-5.1/plugins/interpolatevideo/opticflow.C
cinelerra-5.1/plugins/interpolatevideo/opticflow.h
cinelerra-5.1/plugins/motion-cv/.deps/motion.Plo [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/.deps/motionwindow.Plo [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/.libs/motion.la [new symlink]
cinelerra-5.1/plugins/motion-cv/.libs/motion.lai [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/.libs/motion.so [new file with mode: 0755]
cinelerra-5.1/plugins/motion-cv/Makefile [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/motion-cv.C [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/motion-cv.C.orig [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/motion-cv.h [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/motionwindow-cv.C [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/motionwindow-cv.h [new file with mode: 0644]
cinelerra-5.1/plugins/motion-cv/picon.png [new file with mode: 0644]
cinelerra-5.1/plugins/motion-hv/Makefile [new file with mode: 0644]
cinelerra-5.1/plugins/motion-hv/motion-hv.C [moved from cinelerra-5.1/plugins/motion.new/motion.C with 60% similarity]
cinelerra-5.1/plugins/motion-hv/motion-hv.h [moved from cinelerra-5.1/plugins/motion.new/motion.h with 69% similarity]
cinelerra-5.1/plugins/motion-hv/motion-hv.inc [moved from cinelerra-5.1/plugins/motion.new/motion.inc with 90% similarity]
cinelerra-5.1/plugins/motion-hv/motionscan-hv.C [new file with mode: 0644]
cinelerra-5.1/plugins/motion-hv/motionscan-hv.h [moved from cinelerra-5.1/plugins/motion.new/motionscan.h with 62% similarity]
cinelerra-5.1/plugins/motion-hv/motionscan-hv.inc [moved from cinelerra-5.1/plugins/motion.new/motionscan.inc with 92% similarity]
cinelerra-5.1/plugins/motion-hv/motionwindow-hv.C [moved from cinelerra-5.1/plugins/motion.new/motionwindow.C with 60% similarity]
cinelerra-5.1/plugins/motion-hv/motionwindow-hv.h [new file with mode: 0644]
cinelerra-5.1/plugins/motion-hv/motionwindow-hv.inc [moved from cinelerra-5.1/plugins/motion.new/motionwindow.inc with 89% similarity]
cinelerra-5.1/plugins/motion-hv/picon.png [new file with mode: 0644]
cinelerra-5.1/plugins/motion-hv/theme_suv.png [new file with mode: 0644]
cinelerra-5.1/plugins/motion.new/Makefile [deleted file]
cinelerra-5.1/plugins/motion.new/motionscan.C [deleted file]
cinelerra-5.1/plugins/motion.new/motionwindow.h [deleted file]
cinelerra-5.1/plugins/motion/motion.C
cinelerra-5.1/plugins/motion/motion.h
cinelerra-5.1/plugins/motion/motion.inc
cinelerra-5.1/plugins/motion/motionscan.C
cinelerra-5.1/plugins/motion/motionscan.h
cinelerra-5.1/plugins/motion/motionscan.inc
cinelerra-5.1/plugins/motion/motionwindow.C
cinelerra-5.1/plugins/motion/motionwindow.h
cinelerra-5.1/plugins/motion/motionwindow.inc
cinelerra-5.1/plugins/motion/opencvwrapper.C
cinelerra-5.1/plugins/motion/opencvwrapper.h
cinelerra-5.1/plugins/motion/rotatescan.C [deleted file]
cinelerra-5.1/plugins/motion/rotatescan.h [deleted file]
cinelerra-5.1/plugins/motion/rotatescan.inc [deleted file]
cinelerra-5.1/plugins/motion2point/Makefile
cinelerra-5.1/plugins/motion2point/motion.C
cinelerra-5.1/plugins/motion2point/motion.h
cinelerra-5.1/plugins/motion2point/motionscan-hv.C [new symlink]
cinelerra-5.1/plugins/motion2point/motionscan-hv.h [new symlink]
cinelerra-5.1/plugins/motion2point/motionscan-hv.inc [new symlink]
cinelerra-5.1/plugins/motion2point/motionscan.C [deleted symlink]
cinelerra-5.1/plugins/motion2point/motionscan.h [deleted symlink]
cinelerra-5.1/plugins/motion2point/motionscan.inc [deleted symlink]
cinelerra-5.1/plugins/motion2point/motionwindow.C
cinelerra-5.1/thirdparty/Makefile

index 16c6409b9653154c54c5d91d20736a2d549ad834..9b468bf4f8ea599718bb195e0e94c908b9ada180 100644 (file)
@@ -1949,7 +1949,7 @@ int FFMPEG::encode_activate()
                    (ret=avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE)) < 0 ) {
                        ff_err(ret, "FFMPEG::encode_activate: err opening : %s\n",
                                fmt_ctx->filename);
-                       return 1;
+                       return -1;
                }
 
                AVDictionary *fopts = 0;
@@ -1961,7 +1961,7 @@ int FFMPEG::encode_activate()
                if( ret < 0 ) {
                        ff_err(ret, "FFMPEG::encode_activate: write header failed %s\n",
                                fmt_ctx->filename);
-                       return 1;
+                       return -1;
                }
                encoding = 1;
        }
diff --git a/cinelerra-5.1/ffmpeg/audio/f4v.dfl b/cinelerra-5.1/ffmpeg/audio/f4v.dfl
new file mode 100644 (file)
index 0000000..8b64dbf
--- /dev/null
@@ -0,0 +1 @@
+mp3.f4v
diff --git a/cinelerra-5.1/ffmpeg/audio/flv.dfl b/cinelerra-5.1/ffmpeg/audio/flv.dfl
new file mode 100644 (file)
index 0000000..da751b7
--- /dev/null
@@ -0,0 +1 @@
+mp3.flv
diff --git a/cinelerra-5.1/ffmpeg/audio/mp3.f4v b/cinelerra-5.1/ffmpeg/audio/mp3.f4v
new file mode 100644 (file)
index 0000000..f524cf0
--- /dev/null
@@ -0,0 +1 @@
+f4v libmp3lame
diff --git a/cinelerra-5.1/ffmpeg/audio/mp3.flv b/cinelerra-5.1/ffmpeg/audio/mp3.flv
new file mode 100644 (file)
index 0000000..05d193c
--- /dev/null
@@ -0,0 +1,2 @@
+flv libmp3lame
+# sample rate must be: 44100 or 22050 or 11025
index 73021c587360d7b12ca65fdf06c95fd10cc73cfd..79301da35c3684023ca565fdc322f998ab874d1e 100644 (file)
@@ -1,3 +1,4 @@
 # apply at init encode
+loglevel=error
 threads=auto
 side_data_only_packets=1
diff --git a/cinelerra-5.1/ffmpeg/flv.dfl b/cinelerra-5.1/ffmpeg/flv.dfl
new file mode 100644 (file)
index 0000000..da751b7
--- /dev/null
@@ -0,0 +1 @@
+mp3.flv
diff --git a/cinelerra-5.1/ffmpeg/video/avi.xvid b/cinelerra-5.1/ffmpeg/video/avi.xvid
new file mode 100644 (file)
index 0000000..acb78bf
--- /dev/null
@@ -0,0 +1,2 @@
+avi mpeg4
+vtag xvid
diff --git a/cinelerra-5.1/ffmpeg/video/f4v.dfl b/cinelerra-5.1/ffmpeg/video/f4v.dfl
new file mode 100644 (file)
index 0000000..c1d2d64
--- /dev/null
@@ -0,0 +1 @@
+h264.f4v
diff --git a/cinelerra-5.1/ffmpeg/video/flv.dfl b/cinelerra-5.1/ffmpeg/video/flv.dfl
new file mode 100644 (file)
index 0000000..85a67a7
--- /dev/null
@@ -0,0 +1 @@
+flv.flv
diff --git a/cinelerra-5.1/ffmpeg/video/flv.flv b/cinelerra-5.1/ffmpeg/video/flv.flv
new file mode 100644 (file)
index 0000000..46af192
--- /dev/null
@@ -0,0 +1 @@
+flv flv
diff --git a/cinelerra-5.1/ffmpeg/video/h264.f4v b/cinelerra-5.1/ffmpeg/video/h264.f4v
new file mode 100644 (file)
index 0000000..664351d
--- /dev/null
@@ -0,0 +1,5 @@
+f4v libx264
+profile=baseline
+level=3.0
+preset=medium
+x264opts keyint=25:min-keyint=4:qpmin=3:qpmax=33:qp_step=4:merange=8
diff --git a/cinelerra-5.1/ffmpeg/video/xvid.dfl b/cinelerra-5.1/ffmpeg/video/xvid.dfl
new file mode 100644 (file)
index 0000000..da30cb2
--- /dev/null
@@ -0,0 +1 @@
+avi.xvid
index 3dbe03f1cff0f0236acb4f38ea9baaf06194471e..d8fdbbd0adf00452e632ca72bdeeee8de2ab1083 100644 (file)
@@ -37,9 +37,9 @@ plugin_dirs += video_tools
 video_tools := blur decimate delayvideo denoisemjpeg denoisevideo downsample \
        fieldframe flash framefield freezeframe greycstoration interpolatepixels \
        interpolatevideo invertvideo linearblur loopvideo motion2 motionblur \
-       motion overlay radialblur reframe reframert reroute reversevideo \
-       seltempavg sharpen spectrogram svg titler timeavg timefront unsharp \
-       videoscope wave zoomblur
+       motion motion-cv motion-hv overlay radialblur reframe reframert reroute \
+       reversevideo seltempavg sharpen spectrogram svg titler timeavg timefront \
+       unsharp videoscope wave zoomblur
 
 plugin_dirs += blending
 blending := chromakeyhsv chromakey diffkey
index c233f06c66693e0ba10146644db5f8cd8b001732..5bac9134d3d10848de34cec26c398394e036179b 100644 (file)
@@ -78,6 +78,8 @@ DIRS = \
        loopaudio \
        loopvideo \
        motion \
+       motion-cv \
+       motion-hv \
        motion2point \
        motionblur \
        normalize \
index 98baa20f814e1007ec8a20664c14a8bae03ea10a..3b50feb2271a55ecd9bfce5302083df399a91b95 100644 (file)
@@ -3,7 +3,9 @@ include ../../plugin_defs
 OBJS = $(OBJDIR)/interpolatevideo.o \
        $(OBJDIR)/interpolatewindow.o \
        $(OBJDIR)/opticflow.o \
-       $(OBJDIR)/motionscan.o
+       $(OBJDIR)/motionscan-hv.o
+
+CFLAGS += -DMotionScan=MotionHVScan
 
 PLUGIN = interpolatevideo
 
@@ -13,4 +15,4 @@ include ../../plugin_config
 $(OBJDIR)/interpolatevideo.o: interpolatevideo.C
 $(OBJDIR)/interpolatewindow.o: interpolatewindow.C
 $(OBJDIR)/opticflow.o: opticflow.C
-$(OBJDIR)/motionscan.o: motionscan.C motionscan.h
+$(OBJDIR)/motionscan-hv.o: motionscan-hv.C motionscan-hv.h
index 017be8d51811fbb0d1d229efded3c6dd124d4540..9e553ac3e70d5168b699836beb6070730db25990 100644 (file)
@@ -24,7 +24,7 @@
 #include "interpolatevideo.h"
 #include "interpolatewindow.h"
 #include "language.h"
-#include "motionscan.h"
+#include "motionscan-hv.h"
 #include "opticflow.h"
 #include "transportque.inc"
 #include <unistd.h>
diff --git a/cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.C b/cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.C
new file mode 120000 (symlink)
index 0000000..898c188
--- /dev/null
@@ -0,0 +1 @@
+../motion-hv/motionscan-hv.C
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.h b/cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.h
new file mode 120000 (symlink)
index 0000000..d5eb987
--- /dev/null
@@ -0,0 +1 @@
+../motion-hv/motionscan-hv.h
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.inc b/cinelerra-5.1/plugins/interpolatevideo/motionscan-hv.inc
new file mode 120000 (symlink)
index 0000000..4c59354
--- /dev/null
@@ -0,0 +1 @@
+../motion-hv/motionscan-hv.inc
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/interpolatevideo/motionscan.C b/cinelerra-5.1/plugins/interpolatevideo/motionscan.C
deleted file mode 120000 (symlink)
index 4ac1472..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../motion/motionscan.C
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/interpolatevideo/motionscan.h b/cinelerra-5.1/plugins/interpolatevideo/motionscan.h
deleted file mode 120000 (symlink)
index 9461913..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../motion/motionscan.h
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/interpolatevideo/motionscan.inc b/cinelerra-5.1/plugins/interpolatevideo/motionscan.inc
deleted file mode 120000 (symlink)
index e4b8d55..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../motion/motionscan.inc
\ No newline at end of file
index bce991b06c6fa1fe2855ea3f0e5611b7503de698..9f94d6be6a7c872876391e5a02b6ca729d53974e 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "clip.h"
 #include "interpolatevideo.h"
-#include "motionscan.h"
+#include "motionscan-hv.h"
 #include "opticflow.h"
 
 #include <sys/time.h>
index bbea19dfec2a318c0ee564bbaa20236eb54536b9..6e611fc515a2f2382d4e12f9835ab35eaf8f1c31 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "interpolatevideo.inc"
 #include "loadbalance.h"
-#include "motionscan.inc"
+#include "motionscan-hv.inc"
 #include "opticflow.inc"
 
 // Need a 2nd table if a large number of packages
diff --git a/cinelerra-5.1/plugins/motion-cv/.deps/motion.Plo b/cinelerra-5.1/plugins/motion-cv/.deps/motion.Plo
new file mode 100644 (file)
index 0000000..22e9e74
--- /dev/null
@@ -0,0 +1,691 @@
+motion.lo: motion.C /usr/include/stdc-predef.h ../../cinelerra/affine.h \
+ ../../cinelerra/affine.inc ../../cinelerra/loadbalance.h \
+ ../../guicast/condition.inc ../../guicast/mutex.inc \
+ ../../guicast/thread.h /usr/include/pthread.h /usr/include/features.h \
+ /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/types.h \
+ /usr/include/bits/typesizes.h /usr/include/bits/byteswap-16.h \
+ /usr/include/sched.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h \
+ /usr/include/time.h /usr/include/bits/sched.h /usr/include/bits/time.h \
+ /usr/include/bits/timex.h /usr/include/xlocale.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h \
+ ../../guicast/vframe.inc ../../guicast/bcdisplayinfo.h \
+ /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \
+ /usr/include/wchar.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-float.h \
+ /usr/include/X11/Xlib.h /usr/include/X11/X.h \
+ /usr/include/X11/Xfuncproto.h /usr/include/X11/Xosdefs.h \
+ ../../guicast/clip.h ../../guicast/bchash.h \
+ ../../guicast/bcwindowbase.inc ../../guicast/hashcache.inc \
+ ../../guicast/units.h ../../guicast/sizes.h /usr/include/math.h \
+ /usr/include/bits/math-vector.h /usr/include/bits/libm-simd-decl-stubs.h \
+ /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \
+ /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \
+ /usr/include/bits/nan.h /usr/include/bits/mathdef.h \
+ /usr/include/bits/mathcalls.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h \
+ ../../cinelerra/filexml.h ../../guicast/sizes.h \
+ ../../cinelerra/keyframe.h ../../cinelerra/auto.h \
+ ../../cinelerra/auto.inc ../../cinelerra/edl.inc ../../guicast/guicast.h \
+ ../../guicast/bcbar.h ../../guicast/bcsubwindow.h \
+ ../../guicast/arraylist.h ../../guicast/bcwindowbase.h ../../config.h \
+ ../../guicast/bcbar.inc ../../guicast/bcbitmap.inc \
+ ../../guicast/bcbutton.inc ../../guicast/bccapture.inc \
+ ../../guicast/bcclipboard.inc ../../guicast/bccmodels.inc \
+ ../../guicast/bcdragwindow.inc ../../guicast/bcfilebox.inc \
+ ../../guicast/bclistbox.inc ../../guicast/bcmenubar.inc \
+ ../../guicast/bcmeter.inc ../../guicast/bcpan.inc \
+ ../../guicast/bcpbuffer.inc ../../guicast/bcpixmap.inc \
+ ../../guicast/bcpopup.inc ../../guicast/bcpopupmenu.inc \
+ ../../guicast/bcpot.inc ../../guicast/bcprogress.inc \
+ ../../guicast/bcrelocatablewidget.h ../../guicast/bcrepeater.inc \
+ ../../guicast/bcresources.inc ../../guicast/bcscrollbar.inc \
+ ../../guicast/bcslider.inc ../../guicast/bcsubwindow.inc \
+ ../../guicast/bcsynchronous.inc ../../guicast/bctextbox.inc \
+ ../../guicast/bctimer.inc ../../guicast/bctitle.inc \
+ ../../guicast/bctoggle.inc ../../guicast/bctumble.inc \
+ ../../guicast/bcwidgetgrid.inc ../../guicast/bcwindow.inc \
+ ../../guicast/bcwindowevents.inc ../../guicast/condition.inc \
+ ../../guicast/bchash.inc ../../guicast/linklist.h \
+ ../../guicast/mutex.inc ../../guicast/vframe.inc \
+ /usr/include/X11/Xatom.h /usr/include/X11/Xft/Xft.h \
+ /usr/include/freetype2/ft2build.h \
+ /usr/include/freetype2/config/ftheader.h \
+ /usr/include/freetype2/freetype.h \
+ /usr/include/freetype2/config/ftconfig.h \
+ /usr/include/freetype2/config/ftconfig-64.h \
+ /usr/include/freetype2/config/ftoption.h \
+ /usr/include/freetype2/config/ftstdlib.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/syslimits.h \
+ /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+ /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+ /usr/include/bits/posix2_lim.h /usr/include/bits/xopen_lim.h \
+ /usr/include/string.h /usr/include/setjmp.h \
+ /usr/include/freetype2/fttypes.h /usr/include/freetype2/ftsystem.h \
+ /usr/include/freetype2/ftimage.h /usr/include/freetype2/fterrors.h \
+ /usr/include/freetype2/ftmoderr.h /usr/include/freetype2/fterrdef.h \
+ /usr/include/fontconfig/fontconfig.h /usr/include/sys/stat.h \
+ /usr/include/bits/stat.h /usr/include/X11/extensions/Xrender.h \
+ /usr/include/X11/Xutil.h /usr/include/X11/keysym.h \
+ /usr/include/X11/keysymdef.h /usr/include/X11/extensions/render.h \
+ /usr/include/X11/Xdefs.h /usr/include/X11/Xft/XftCompat.h \
+ /usr/include/X11/cursorfont.h /usr/include/X11/extensions/xf86vmode.h \
+ /usr/include/X11/Xmd.h /usr/include/X11/extensions/xf86vm.h \
+ /usr/include/GL/glx.h /usr/include/GL/gl.h /usr/include/GL/glext.h \
+ /usr/include/inttypes.h /usr/include/GL/glxext.h \
+ ../../guicast/bcbitmap.h /usr/include/sys/ipc.h \
+ /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h \
+ /usr/include/sys/shm.h /usr/include/bits/shm.h \
+ /usr/include/X11/extensions/XShm.h /usr/include/X11/extensions/shm.h \
+ /usr/include/X11/extensions/Xvlib.h /usr/include/X11/extensions/Xv.h \
+ ../../guicast/colors.h ../../guicast/bcbutton.h \
+ ../../guicast/bcclipboard.h ../../guicast/thread.h \
+ ../../guicast/bcdragwindow.h ../../guicast/bcpopup.h \
+ ../../guicast/bclistboxitem.h ../../guicast/vframe.h \
+ ../../guicast/bctexture.inc ../../quicktime/colormodels.h \
+ ../../guicast/bccmodels.h ../../guicast/bcpan.h \
+ ../../guicast/rotateframe.inc ../../guicast/bcfilebox.h \
+ ../../guicast/bcdelete.inc ../../guicast/bclistboxitem.inc \
+ ../../guicast/bcnewfolder.inc ../../guicast/bctextbox.h \
+ ../../guicast/bclistbox.h ../../guicast/bcscrollbar.h \
+ ../../guicast/bctoggle.h ../../guicast/fonts.h ../../guicast/bctumble.h \
+ ../../guicast/bcwindow.h ../../guicast/filesystem.inc \
+ ../../guicast/bcmenu.h ../../guicast/bcmenuitem.inc \
+ ../../guicast/bcmenupopup.inc ../../guicast/bcmenubar.h \
+ ../../guicast/bcmenu.inc ../../guicast/bcmenuitem.h \
+ ../../guicast/bcmenupopup.h ../../guicast/bcmeter.h \
+ ../../guicast/bcpopupmenu.h ../../guicast/bcpot.h \
+ ../../guicast/bcpixmap.h ../../guicast/bcprogress.h \
+ ../../guicast/bcrecentlist.h ../../guicast/bcresources.h \
+ ../../guicast/bcdisplayinfo.inc ../../guicast/bcfontentry.inc \
+ ../../guicast/bcsignals.inc ../../guicast/bcslider.h \
+ ../../guicast/bcsynchronous.h ../../guicast/bctexture.h \
+ ../../guicast/bctheme.h ../../guicast/bctitle.h ../../guicast/bctimer.h \
+ /usr/include/sys/time.h ../../guicast/error.h ../../guicast/debug.h \
+ ../../cinelerra/filexml.inc ../../cinelerra/autos.inc \
+ ../../cinelerra/keyframes.inc ../../cinelerra/messages.inc \
+ ../../guicast/language.h /usr/include/libintl.h motion.h \
+ ../../cinelerra/affine.inc ../../guicast/bchash.inc \
+ ../../cinelerra/filexml.inc ../../cinelerra/keyframe.inc \
+ ../../cinelerra/loadbalance.h motionwindow.inc \
+ ../../cinelerra/overlayframe.inc ../../cinelerra/pluginvclient.h \
+ ../../cinelerra/maxbuffers.h ../../cinelerra/pluginclient.h \
+ ../../guicast/arraylist.h ../../guicast/condition.h \
+ ../../cinelerra/edlsession.inc ../../cinelerra/keyframe.h \
+ ../../cinelerra/mainprogress.inc ../../cinelerra/plugincommands.h \
+ ../../cinelerra/pluginserver.inc ../../cinelerra/theme.inc \
+ ../../guicast/vframe.h ../../guicast/rotateframe.inc motionwindow.h \
+ motion.inc ../../cinelerra/pluginwindow.h ../../guicast/bcwindow.h \
+ ../../guicast/mutex.h ../../cinelerra/overlayframe.h \
+ ../../cinelerra/overlayframe.inc picon_png.h ../../guicast/rotateframe.h \
+ ../../cinelerra/transportque.h ../../cinelerra/canvas.inc \
+ ../../cinelerra/preferences.inc ../../cinelerra/transportque.inc \
+ /usr/include/errno.h /usr/include/bits/errno.h \
+ /usr/include/linux/errno.h /usr/include/asm/errno.h \
+ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
+ /usr/include/unistd.h /usr/include/bits/posix_opt.h \
+ /usr/include/bits/environments.h /usr/include/bits/confname.h \
+ /usr/include/getopt.h
+
+/usr/include/stdc-predef.h:
+
+../../cinelerra/affine.h:
+
+../../cinelerra/affine.inc:
+
+../../cinelerra/loadbalance.h:
+
+../../guicast/condition.inc:
+
+../../guicast/mutex.inc:
+
+../../guicast/thread.h:
+
+/usr/include/pthread.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/byteswap-16.h:
+
+/usr/include/sched.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/setjmp.h:
+
+../../guicast/vframe.inc:
+
+../../guicast/bcdisplayinfo.h:
+
+/usr/include/stdio.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/wchar.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/sigset.h:
+
+/usr/include/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/include/X11/Xlib.h:
+
+/usr/include/X11/X.h:
+
+/usr/include/X11/Xfuncproto.h:
+
+/usr/include/X11/Xosdefs.h:
+
+../../guicast/clip.h:
+
+../../guicast/bchash.h:
+
+../../guicast/bcwindowbase.inc:
+
+../../guicast/hashcache.inc:
+
+../../guicast/units.h:
+
+../../guicast/sizes.h:
+
+/usr/include/math.h:
+
+/usr/include/bits/math-vector.h:
+
+/usr/include/bits/libm-simd-decl-stubs.h:
+
+/usr/include/bits/huge_val.h:
+
+/usr/include/bits/huge_valf.h:
+
+/usr/include/bits/huge_vall.h:
+
+/usr/include/bits/inf.h:
+
+/usr/include/bits/nan.h:
+
+/usr/include/bits/mathdef.h:
+
+/usr/include/bits/mathcalls.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/wchar.h:
+
+../../cinelerra/filexml.h:
+
+../../guicast/sizes.h:
+
+../../cinelerra/keyframe.h:
+
+../../cinelerra/auto.h:
+
+../../cinelerra/auto.inc:
+
+../../cinelerra/edl.inc:
+
+../../guicast/guicast.h:
+
+../../guicast/bcbar.h:
+
+../../guicast/bcsubwindow.h:
+
+../../guicast/arraylist.h:
+
+../../guicast/bcwindowbase.h:
+
+../../config.h:
+
+../../guicast/bcbar.inc:
+
+../../guicast/bcbitmap.inc:
+
+../../guicast/bcbutton.inc:
+
+../../guicast/bccapture.inc:
+
+../../guicast/bcclipboard.inc:
+
+../../guicast/bccmodels.inc:
+
+../../guicast/bcdragwindow.inc:
+
+../../guicast/bcfilebox.inc:
+
+../../guicast/bclistbox.inc:
+
+../../guicast/bcmenubar.inc:
+
+../../guicast/bcmeter.inc:
+
+../../guicast/bcpan.inc:
+
+../../guicast/bcpbuffer.inc:
+
+../../guicast/bcpixmap.inc:
+
+../../guicast/bcpopup.inc:
+
+../../guicast/bcpopupmenu.inc:
+
+../../guicast/bcpot.inc:
+
+../../guicast/bcprogress.inc:
+
+../../guicast/bcrelocatablewidget.h:
+
+../../guicast/bcrepeater.inc:
+
+../../guicast/bcresources.inc:
+
+../../guicast/bcscrollbar.inc:
+
+../../guicast/bcslider.inc:
+
+../../guicast/bcsubwindow.inc:
+
+../../guicast/bcsynchronous.inc:
+
+../../guicast/bctextbox.inc:
+
+../../guicast/bctimer.inc:
+
+../../guicast/bctitle.inc:
+
+../../guicast/bctoggle.inc:
+
+../../guicast/bctumble.inc:
+
+../../guicast/bcwidgetgrid.inc:
+
+../../guicast/bcwindow.inc:
+
+../../guicast/bcwindowevents.inc:
+
+../../guicast/condition.inc:
+
+../../guicast/bchash.inc:
+
+../../guicast/linklist.h:
+
+../../guicast/mutex.inc:
+
+../../guicast/vframe.inc:
+
+/usr/include/X11/Xatom.h:
+
+/usr/include/X11/Xft/Xft.h:
+
+/usr/include/freetype2/ft2build.h:
+
+/usr/include/freetype2/config/ftheader.h:
+
+/usr/include/freetype2/freetype.h:
+
+/usr/include/freetype2/config/ftconfig.h:
+
+/usr/include/freetype2/config/ftconfig-64.h:
+
+/usr/include/freetype2/config/ftoption.h:
+
+/usr/include/freetype2/config/ftstdlib.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/limits.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/syslimits.h:
+
+/usr/include/limits.h:
+
+/usr/include/bits/posix1_lim.h:
+
+/usr/include/bits/local_lim.h:
+
+/usr/include/linux/limits.h:
+
+/usr/include/bits/posix2_lim.h:
+
+/usr/include/bits/xopen_lim.h:
+
+/usr/include/string.h:
+
+/usr/include/setjmp.h:
+
+/usr/include/freetype2/fttypes.h:
+
+/usr/include/freetype2/ftsystem.h:
+
+/usr/include/freetype2/ftimage.h:
+
+/usr/include/freetype2/fterrors.h:
+
+/usr/include/freetype2/ftmoderr.h:
+
+/usr/include/freetype2/fterrdef.h:
+
+/usr/include/fontconfig/fontconfig.h:
+
+/usr/include/sys/stat.h:
+
+/usr/include/bits/stat.h:
+
+/usr/include/X11/extensions/Xrender.h:
+
+/usr/include/X11/Xutil.h:
+
+/usr/include/X11/keysym.h:
+
+/usr/include/X11/keysymdef.h:
+
+/usr/include/X11/extensions/render.h:
+
+/usr/include/X11/Xdefs.h:
+
+/usr/include/X11/Xft/XftCompat.h:
+
+/usr/include/X11/cursorfont.h:
+
+/usr/include/X11/extensions/xf86vmode.h:
+
+/usr/include/X11/Xmd.h:
+
+/usr/include/X11/extensions/xf86vm.h:
+
+/usr/include/GL/glx.h:
+
+/usr/include/GL/gl.h:
+
+/usr/include/GL/glext.h:
+
+/usr/include/inttypes.h:
+
+/usr/include/GL/glxext.h:
+
+../../guicast/bcbitmap.h:
+
+/usr/include/sys/ipc.h:
+
+/usr/include/bits/ipctypes.h:
+
+/usr/include/bits/ipc.h:
+
+/usr/include/sys/shm.h:
+
+/usr/include/bits/shm.h:
+
+/usr/include/X11/extensions/XShm.h:
+
+/usr/include/X11/extensions/shm.h:
+
+/usr/include/X11/extensions/Xvlib.h:
+
+/usr/include/X11/extensions/Xv.h:
+
+../../guicast/colors.h:
+
+../../guicast/bcbutton.h:
+
+../../guicast/bcclipboard.h:
+
+../../guicast/thread.h:
+
+../../guicast/bcdragwindow.h:
+
+../../guicast/bcpopup.h:
+
+../../guicast/bclistboxitem.h:
+
+../../guicast/vframe.h:
+
+../../guicast/bctexture.inc:
+
+../../quicktime/colormodels.h:
+
+../../guicast/bccmodels.h:
+
+../../guicast/bcpan.h:
+
+../../guicast/rotateframe.inc:
+
+../../guicast/bcfilebox.h:
+
+../../guicast/bcdelete.inc:
+
+../../guicast/bclistboxitem.inc:
+
+../../guicast/bcnewfolder.inc:
+
+../../guicast/bctextbox.h:
+
+../../guicast/bclistbox.h:
+
+../../guicast/bcscrollbar.h:
+
+../../guicast/bctoggle.h:
+
+../../guicast/fonts.h:
+
+../../guicast/bctumble.h:
+
+../../guicast/bcwindow.h:
+
+../../guicast/filesystem.inc:
+
+../../guicast/bcmenu.h:
+
+../../guicast/bcmenuitem.inc:
+
+../../guicast/bcmenupopup.inc:
+
+../../guicast/bcmenubar.h:
+
+../../guicast/bcmenu.inc:
+
+../../guicast/bcmenuitem.h:
+
+../../guicast/bcmenupopup.h:
+
+../../guicast/bcmeter.h:
+
+../../guicast/bcpopupmenu.h:
+
+../../guicast/bcpot.h:
+
+../../guicast/bcpixmap.h:
+
+../../guicast/bcprogress.h:
+
+../../guicast/bcrecentlist.h:
+
+../../guicast/bcresources.h:
+
+../../guicast/bcdisplayinfo.inc:
+
+../../guicast/bcfontentry.inc:
+
+../../guicast/bcsignals.inc:
+
+../../guicast/bcslider.h:
+
+../../guicast/bcsynchronous.h:
+
+../../guicast/bctexture.h:
+
+../../guicast/bctheme.h:
+
+../../guicast/bctitle.h:
+
+../../guicast/bctimer.h:
+
+/usr/include/sys/time.h:
+
+../../guicast/error.h:
+
+../../guicast/debug.h:
+
+../../cinelerra/filexml.inc:
+
+../../cinelerra/autos.inc:
+
+../../cinelerra/keyframes.inc:
+
+../../cinelerra/messages.inc:
+
+../../guicast/language.h:
+
+/usr/include/libintl.h:
+
+motion.h:
+
+../../cinelerra/affine.inc:
+
+../../guicast/bchash.inc:
+
+../../cinelerra/filexml.inc:
+
+../../cinelerra/keyframe.inc:
+
+../../cinelerra/loadbalance.h:
+
+motionwindow.inc:
+
+../../cinelerra/overlayframe.inc:
+
+../../cinelerra/pluginvclient.h:
+
+../../cinelerra/maxbuffers.h:
+
+../../cinelerra/pluginclient.h:
+
+../../guicast/arraylist.h:
+
+../../guicast/condition.h:
+
+../../cinelerra/edlsession.inc:
+
+../../cinelerra/keyframe.h:
+
+../../cinelerra/mainprogress.inc:
+
+../../cinelerra/plugincommands.h:
+
+../../cinelerra/pluginserver.inc:
+
+../../cinelerra/theme.inc:
+
+../../guicast/vframe.h:
+
+../../guicast/rotateframe.inc:
+
+motionwindow.h:
+
+motion.inc:
+
+../../cinelerra/pluginwindow.h:
+
+../../guicast/bcwindow.h:
+
+../../guicast/mutex.h:
+
+../../cinelerra/overlayframe.h:
+
+../../cinelerra/overlayframe.inc:
+
+picon_png.h:
+
+../../guicast/rotateframe.h:
+
+../../cinelerra/transportque.h:
+
+../../cinelerra/canvas.inc:
+
+../../cinelerra/preferences.inc:
+
+../../cinelerra/transportque.inc:
+
+/usr/include/errno.h:
+
+/usr/include/bits/errno.h:
+
+/usr/include/linux/errno.h:
+
+/usr/include/asm/errno.h:
+
+/usr/include/asm-generic/errno.h:
+
+/usr/include/asm-generic/errno-base.h:
+
+/usr/include/unistd.h:
+
+/usr/include/bits/posix_opt.h:
+
+/usr/include/bits/environments.h:
+
+/usr/include/bits/confname.h:
+
+/usr/include/getopt.h:
diff --git a/cinelerra-5.1/plugins/motion-cv/.deps/motionwindow.Plo b/cinelerra-5.1/plugins/motion-cv/.deps/motionwindow.Plo
new file mode 100644 (file)
index 0000000..08a9f0a
--- /dev/null
@@ -0,0 +1,621 @@
+motionwindow.lo: motionwindow.C /usr/include/stdc-predef.h \
+ ../../guicast/bcdisplayinfo.h /usr/include/stdio.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
+ /usr/include/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/endian.h \
+ /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+ /usr/include/bits/byteswap-16.h /usr/include/xlocale.h \
+ /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
+ /usr/include/bits/select.h /usr/include/bits/sigset.h \
+ /usr/include/bits/time.h /usr/include/sys/sysmacros.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
+ /usr/include/bits/stdlib-float.h /usr/include/X11/Xlib.h \
+ /usr/include/X11/X.h /usr/include/X11/Xfuncproto.h \
+ /usr/include/X11/Xosdefs.h ../../guicast/clip.h ../../guicast/language.h \
+ /usr/include/libintl.h motion.h /usr/include/math.h \
+ /usr/include/bits/math-vector.h /usr/include/bits/libm-simd-decl-stubs.h \
+ /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \
+ /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \
+ /usr/include/bits/nan.h /usr/include/bits/mathdef.h \
+ /usr/include/bits/mathcalls.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/string.h \
+ ../../cinelerra/affine.inc ../../guicast/bchash.inc \
+ ../../cinelerra/filexml.inc ../../cinelerra/keyframe.inc \
+ ../../cinelerra/loadbalance.h ../../guicast/condition.inc \
+ ../../guicast/mutex.inc ../../guicast/thread.h /usr/include/pthread.h \
+ /usr/include/sched.h /usr/include/bits/sched.h /usr/include/bits/timex.h \
+ /usr/include/bits/setjmp.h motionwindow.inc \
+ ../../cinelerra/overlayframe.inc ../../cinelerra/pluginvclient.h \
+ ../../cinelerra/maxbuffers.h ../../cinelerra/pluginclient.h \
+ ../../guicast/arraylist.h ../../guicast/condition.h \
+ ../../cinelerra/edlsession.inc ../../cinelerra/keyframe.h \
+ ../../cinelerra/auto.h ../../cinelerra/auto.inc ../../cinelerra/edl.inc \
+ ../../guicast/guicast.h ../../guicast/bcbar.h \
+ ../../guicast/bcsubwindow.h ../../guicast/arraylist.h \
+ ../../guicast/bcwindowbase.h ../../config.h ../../guicast/bcbar.inc \
+ ../../guicast/bcbitmap.inc ../../guicast/bcbutton.inc \
+ ../../guicast/bccapture.inc ../../guicast/bcclipboard.inc \
+ ../../guicast/bccmodels.inc ../../guicast/bcdragwindow.inc \
+ ../../guicast/bcfilebox.inc ../../guicast/bclistbox.inc \
+ ../../guicast/bcmenubar.inc ../../guicast/bcmeter.inc \
+ ../../guicast/bcpan.inc ../../guicast/bcpbuffer.inc \
+ ../../guicast/bcpixmap.inc ../../guicast/bcpopup.inc \
+ ../../guicast/bcpopupmenu.inc ../../guicast/bcpot.inc \
+ ../../guicast/bcprogress.inc ../../guicast/bcrelocatablewidget.h \
+ ../../guicast/bcrepeater.inc ../../guicast/bcresources.inc \
+ ../../guicast/bcscrollbar.inc ../../guicast/bcslider.inc \
+ ../../guicast/bcsubwindow.inc ../../guicast/bcsynchronous.inc \
+ ../../guicast/bctextbox.inc ../../guicast/bctimer.inc \
+ ../../guicast/bctitle.inc ../../guicast/bctoggle.inc \
+ ../../guicast/bctumble.inc ../../guicast/bcwidgetgrid.inc \
+ ../../guicast/bcwindow.inc ../../guicast/bcwindowbase.inc \
+ ../../guicast/bcwindowevents.inc ../../guicast/condition.inc \
+ ../../guicast/bchash.inc ../../guicast/linklist.h \
+ ../../guicast/mutex.inc ../../guicast/vframe.inc \
+ /usr/include/X11/Xatom.h /usr/include/X11/Xft/Xft.h \
+ /usr/include/freetype2/ft2build.h \
+ /usr/include/freetype2/config/ftheader.h \
+ /usr/include/freetype2/freetype.h \
+ /usr/include/freetype2/config/ftconfig.h \
+ /usr/include/freetype2/config/ftconfig-64.h \
+ /usr/include/freetype2/config/ftoption.h \
+ /usr/include/freetype2/config/ftstdlib.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/syslimits.h \
+ /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+ /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+ /usr/include/bits/posix2_lim.h /usr/include/bits/xopen_lim.h \
+ /usr/include/setjmp.h /usr/include/freetype2/fttypes.h \
+ /usr/include/freetype2/ftsystem.h /usr/include/freetype2/ftimage.h \
+ /usr/include/freetype2/fterrors.h /usr/include/freetype2/ftmoderr.h \
+ /usr/include/freetype2/fterrdef.h /usr/include/fontconfig/fontconfig.h \
+ /usr/include/sys/stat.h /usr/include/bits/stat.h \
+ /usr/include/X11/extensions/Xrender.h /usr/include/X11/Xutil.h \
+ /usr/include/X11/keysym.h /usr/include/X11/keysymdef.h \
+ /usr/include/X11/extensions/render.h /usr/include/X11/Xdefs.h \
+ /usr/include/X11/Xft/XftCompat.h /usr/include/X11/cursorfont.h \
+ /usr/include/X11/extensions/xf86vmode.h /usr/include/X11/Xmd.h \
+ /usr/include/X11/extensions/xf86vm.h /usr/include/GL/glx.h \
+ /usr/include/GL/gl.h /usr/include/GL/glext.h /usr/include/inttypes.h \
+ /usr/include/GL/glxext.h ../../guicast/bcbitmap.h /usr/include/sys/ipc.h \
+ /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h \
+ /usr/include/sys/shm.h /usr/include/bits/shm.h \
+ /usr/include/X11/extensions/XShm.h /usr/include/X11/extensions/shm.h \
+ /usr/include/X11/extensions/Xvlib.h /usr/include/X11/extensions/Xv.h \
+ ../../guicast/colors.h ../../guicast/sizes.h ../../guicast/bcbutton.h \
+ ../../guicast/bcclipboard.h ../../guicast/thread.h \
+ ../../guicast/bcdragwindow.h ../../guicast/bcpopup.h \
+ ../../guicast/bclistboxitem.h ../../guicast/vframe.h \
+ ../../guicast/bctexture.inc ../../quicktime/colormodels.h \
+ ../../guicast/bccmodels.h ../../guicast/bcpan.h \
+ ../../guicast/rotateframe.inc ../../guicast/bcfilebox.h \
+ ../../guicast/bcdelete.inc ../../guicast/bclistboxitem.inc \
+ ../../guicast/bcnewfolder.inc ../../guicast/bctextbox.h \
+ ../../guicast/bclistbox.h ../../guicast/bcscrollbar.h \
+ ../../guicast/bctoggle.h ../../guicast/fonts.h ../../guicast/bctumble.h \
+ ../../guicast/bcwindow.h ../../guicast/filesystem.inc \
+ ../../guicast/bcmenu.h ../../guicast/bcmenuitem.inc \
+ ../../guicast/bcmenupopup.inc ../../guicast/bcmenubar.h \
+ ../../guicast/bcmenu.inc ../../guicast/bcmenuitem.h \
+ ../../guicast/bcmenupopup.h ../../guicast/bcmeter.h \
+ ../../guicast/units.h ../../guicast/bcpopupmenu.h ../../guicast/bcpot.h \
+ ../../guicast/bcpixmap.h ../../guicast/bcprogress.h \
+ ../../guicast/bcrecentlist.h ../../guicast/bcresources.h \
+ ../../guicast/bcdisplayinfo.inc ../../guicast/bcfontentry.inc \
+ ../../guicast/bcsignals.inc ../../guicast/hashcache.inc \
+ ../../guicast/bcslider.h ../../guicast/bcsynchronous.h \
+ ../../guicast/bctexture.h ../../guicast/bctheme.h \
+ ../../guicast/bctitle.h ../../guicast/bctimer.h /usr/include/sys/time.h \
+ ../../guicast/error.h ../../guicast/debug.h ../../cinelerra/filexml.inc \
+ ../../cinelerra/autos.inc ../../cinelerra/keyframes.inc \
+ ../../cinelerra/messages.inc ../../cinelerra/mainprogress.inc \
+ ../../cinelerra/plugincommands.h ../../cinelerra/pluginserver.inc \
+ ../../cinelerra/theme.inc ../../guicast/vframe.h \
+ ../../guicast/vframe.inc ../../guicast/rotateframe.inc motionwindow.h \
+ motion.inc ../../cinelerra/pluginwindow.h ../../guicast/bcwindow.h
+
+/usr/include/stdc-predef.h:
+
+../../guicast/bcdisplayinfo.h:
+
+/usr/include/stdio.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/wchar.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/byteswap-16.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/time.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/sigset.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/sys/sysmacros.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/include/X11/Xlib.h:
+
+/usr/include/X11/X.h:
+
+/usr/include/X11/Xfuncproto.h:
+
+/usr/include/X11/Xosdefs.h:
+
+../../guicast/clip.h:
+
+../../guicast/language.h:
+
+/usr/include/libintl.h:
+
+motion.h:
+
+/usr/include/math.h:
+
+/usr/include/bits/math-vector.h:
+
+/usr/include/bits/libm-simd-decl-stubs.h:
+
+/usr/include/bits/huge_val.h:
+
+/usr/include/bits/huge_valf.h:
+
+/usr/include/bits/huge_vall.h:
+
+/usr/include/bits/inf.h:
+
+/usr/include/bits/nan.h:
+
+/usr/include/bits/mathdef.h:
+
+/usr/include/bits/mathcalls.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/string.h:
+
+../../cinelerra/affine.inc:
+
+../../guicast/bchash.inc:
+
+../../cinelerra/filexml.inc:
+
+../../cinelerra/keyframe.inc:
+
+../../cinelerra/loadbalance.h:
+
+../../guicast/condition.inc:
+
+../../guicast/mutex.inc:
+
+../../guicast/thread.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/setjmp.h:
+
+motionwindow.inc:
+
+../../cinelerra/overlayframe.inc:
+
+../../cinelerra/pluginvclient.h:
+
+../../cinelerra/maxbuffers.h:
+
+../../cinelerra/pluginclient.h:
+
+../../guicast/arraylist.h:
+
+../../guicast/condition.h:
+
+../../cinelerra/edlsession.inc:
+
+../../cinelerra/keyframe.h:
+
+../../cinelerra/auto.h:
+
+../../cinelerra/auto.inc:
+
+../../cinelerra/edl.inc:
+
+../../guicast/guicast.h:
+
+../../guicast/bcbar.h:
+
+../../guicast/bcsubwindow.h:
+
+../../guicast/arraylist.h:
+
+../../guicast/bcwindowbase.h:
+
+../../config.h:
+
+../../guicast/bcbar.inc:
+
+../../guicast/bcbitmap.inc:
+
+../../guicast/bcbutton.inc:
+
+../../guicast/bccapture.inc:
+
+../../guicast/bcclipboard.inc:
+
+../../guicast/bccmodels.inc:
+
+../../guicast/bcdragwindow.inc:
+
+../../guicast/bcfilebox.inc:
+
+../../guicast/bclistbox.inc:
+
+../../guicast/bcmenubar.inc:
+
+../../guicast/bcmeter.inc:
+
+../../guicast/bcpan.inc:
+
+../../guicast/bcpbuffer.inc:
+
+../../guicast/bcpixmap.inc:
+
+../../guicast/bcpopup.inc:
+
+../../guicast/bcpopupmenu.inc:
+
+../../guicast/bcpot.inc:
+
+../../guicast/bcprogress.inc:
+
+../../guicast/bcrelocatablewidget.h:
+
+../../guicast/bcrepeater.inc:
+
+../../guicast/bcresources.inc:
+
+../../guicast/bcscrollbar.inc:
+
+../../guicast/bcslider.inc:
+
+../../guicast/bcsubwindow.inc:
+
+../../guicast/bcsynchronous.inc:
+
+../../guicast/bctextbox.inc:
+
+../../guicast/bctimer.inc:
+
+../../guicast/bctitle.inc:
+
+../../guicast/bctoggle.inc:
+
+../../guicast/bctumble.inc:
+
+../../guicast/bcwidgetgrid.inc:
+
+../../guicast/bcwindow.inc:
+
+../../guicast/bcwindowbase.inc:
+
+../../guicast/bcwindowevents.inc:
+
+../../guicast/condition.inc:
+
+../../guicast/bchash.inc:
+
+../../guicast/linklist.h:
+
+../../guicast/mutex.inc:
+
+../../guicast/vframe.inc:
+
+/usr/include/X11/Xatom.h:
+
+/usr/include/X11/Xft/Xft.h:
+
+/usr/include/freetype2/ft2build.h:
+
+/usr/include/freetype2/config/ftheader.h:
+
+/usr/include/freetype2/freetype.h:
+
+/usr/include/freetype2/config/ftconfig.h:
+
+/usr/include/freetype2/config/ftconfig-64.h:
+
+/usr/include/freetype2/config/ftoption.h:
+
+/usr/include/freetype2/config/ftstdlib.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/limits.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/syslimits.h:
+
+/usr/include/limits.h:
+
+/usr/include/bits/posix1_lim.h:
+
+/usr/include/bits/local_lim.h:
+
+/usr/include/linux/limits.h:
+
+/usr/include/bits/posix2_lim.h:
+
+/usr/include/bits/xopen_lim.h:
+
+/usr/include/setjmp.h:
+
+/usr/include/freetype2/fttypes.h:
+
+/usr/include/freetype2/ftsystem.h:
+
+/usr/include/freetype2/ftimage.h:
+
+/usr/include/freetype2/fterrors.h:
+
+/usr/include/freetype2/ftmoderr.h:
+
+/usr/include/freetype2/fterrdef.h:
+
+/usr/include/fontconfig/fontconfig.h:
+
+/usr/include/sys/stat.h:
+
+/usr/include/bits/stat.h:
+
+/usr/include/X11/extensions/Xrender.h:
+
+/usr/include/X11/Xutil.h:
+
+/usr/include/X11/keysym.h:
+
+/usr/include/X11/keysymdef.h:
+
+/usr/include/X11/extensions/render.h:
+
+/usr/include/X11/Xdefs.h:
+
+/usr/include/X11/Xft/XftCompat.h:
+
+/usr/include/X11/cursorfont.h:
+
+/usr/include/X11/extensions/xf86vmode.h:
+
+/usr/include/X11/Xmd.h:
+
+/usr/include/X11/extensions/xf86vm.h:
+
+/usr/include/GL/glx.h:
+
+/usr/include/GL/gl.h:
+
+/usr/include/GL/glext.h:
+
+/usr/include/inttypes.h:
+
+/usr/include/GL/glxext.h:
+
+../../guicast/bcbitmap.h:
+
+/usr/include/sys/ipc.h:
+
+/usr/include/bits/ipctypes.h:
+
+/usr/include/bits/ipc.h:
+
+/usr/include/sys/shm.h:
+
+/usr/include/bits/shm.h:
+
+/usr/include/X11/extensions/XShm.h:
+
+/usr/include/X11/extensions/shm.h:
+
+/usr/include/X11/extensions/Xvlib.h:
+
+/usr/include/X11/extensions/Xv.h:
+
+../../guicast/colors.h:
+
+../../guicast/sizes.h:
+
+../../guicast/bcbutton.h:
+
+../../guicast/bcclipboard.h:
+
+../../guicast/thread.h:
+
+../../guicast/bcdragwindow.h:
+
+../../guicast/bcpopup.h:
+
+../../guicast/bclistboxitem.h:
+
+../../guicast/vframe.h:
+
+../../guicast/bctexture.inc:
+
+../../quicktime/colormodels.h:
+
+../../guicast/bccmodels.h:
+
+../../guicast/bcpan.h:
+
+../../guicast/rotateframe.inc:
+
+../../guicast/bcfilebox.h:
+
+../../guicast/bcdelete.inc:
+
+../../guicast/bclistboxitem.inc:
+
+../../guicast/bcnewfolder.inc:
+
+../../guicast/bctextbox.h:
+
+../../guicast/bclistbox.h:
+
+../../guicast/bcscrollbar.h:
+
+../../guicast/bctoggle.h:
+
+../../guicast/fonts.h:
+
+../../guicast/bctumble.h:
+
+../../guicast/bcwindow.h:
+
+../../guicast/filesystem.inc:
+
+../../guicast/bcmenu.h:
+
+../../guicast/bcmenuitem.inc:
+
+../../guicast/bcmenupopup.inc:
+
+../../guicast/bcmenubar.h:
+
+../../guicast/bcmenu.inc:
+
+../../guicast/bcmenuitem.h:
+
+../../guicast/bcmenupopup.h:
+
+../../guicast/bcmeter.h:
+
+../../guicast/units.h:
+
+../../guicast/bcpopupmenu.h:
+
+../../guicast/bcpot.h:
+
+../../guicast/bcpixmap.h:
+
+../../guicast/bcprogress.h:
+
+../../guicast/bcrecentlist.h:
+
+../../guicast/bcresources.h:
+
+../../guicast/bcdisplayinfo.inc:
+
+../../guicast/bcfontentry.inc:
+
+../../guicast/bcsignals.inc:
+
+../../guicast/hashcache.inc:
+
+../../guicast/bcslider.h:
+
+../../guicast/bcsynchronous.h:
+
+../../guicast/bctexture.h:
+
+../../guicast/bctheme.h:
+
+../../guicast/bctitle.h:
+
+../../guicast/bctimer.h:
+
+/usr/include/sys/time.h:
+
+../../guicast/error.h:
+
+../../guicast/debug.h:
+
+../../cinelerra/filexml.inc:
+
+../../cinelerra/autos.inc:
+
+../../cinelerra/keyframes.inc:
+
+../../cinelerra/messages.inc:
+
+../../cinelerra/mainprogress.inc:
+
+../../cinelerra/plugincommands.h:
+
+../../cinelerra/pluginserver.inc:
+
+../../cinelerra/theme.inc:
+
+../../guicast/vframe.h:
+
+../../guicast/vframe.inc:
+
+../../guicast/rotateframe.inc:
+
+motionwindow.h:
+
+motion.inc:
+
+../../cinelerra/pluginwindow.h:
+
+../../guicast/bcwindow.h:
diff --git a/cinelerra-5.1/plugins/motion-cv/.libs/motion.la b/cinelerra-5.1/plugins/motion-cv/.libs/motion.la
new file mode 120000 (symlink)
index 0000000..3b77efb
--- /dev/null
@@ -0,0 +1 @@
+../motion.la
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/motion-cv/.libs/motion.lai b/cinelerra-5.1/plugins/motion-cv/.libs/motion.lai
new file mode 100644 (file)
index 0000000..c21dbc4
--- /dev/null
@@ -0,0 +1,41 @@
+# motion.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.6
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='motion.so'
+
+# Names of this library.
+library_names='motion.so motion.so motion.so'
+
+# The name of the static archive.
+old_library=''
+
+# Linker flags that cannot go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=' -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/a52dec-0.7.4/liba52/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/faac-1.28/common/mp4v2 -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/faac-1.28/libfaac/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/faad2-2.7/common/mp4ff -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/faad2-2.7/libfaad/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/lame-3.99.5/libmp3lame/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/lame-3.99.5/mpglib/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/libuuid-1.0.3/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/mjpegtools-2.1.0/lavtools/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/mjpegtools-2.1.0/mpeg2enc/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/mjpegtools-2.1.0/mplex/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/mjpegtools-2.1.0/utils/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/mjpegtools-2.1.0/utils/mmxsse/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/mjpegtools-2.1.0/yuvfilters/.libs -L/mnt0/build5/cinelerra-cv/thirdparty/../thirdparty/x264-snapshot-20160220-2245-stable -ldl -lpthread'
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for motion.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=yes
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/usr/local/lib/cinelerra'
diff --git a/cinelerra-5.1/plugins/motion-cv/.libs/motion.so b/cinelerra-5.1/plugins/motion-cv/.libs/motion.so
new file mode 100755 (executable)
index 0000000..2829316
Binary files /dev/null and b/cinelerra-5.1/plugins/motion-cv/.libs/motion.so differ
diff --git a/cinelerra-5.1/plugins/motion-cv/Makefile b/cinelerra-5.1/plugins/motion-cv/Makefile
new file mode 100644 (file)
index 0000000..a090016
--- /dev/null
@@ -0,0 +1,13 @@
+include ../../plugin_defs
+
+OBJS := \
+       $(OBJDIR)/motion-cv.o \
+       $(OBJDIR)/motionwindow-cv.o
+
+PLUGIN = motion-cv
+
+include ../../plugin_config
+
+$(OBJDIR)/motion-cv.o: motion-cv.C
+$(OBJDIR)/motionwindow-cv.o: motionwindow-cv.C
+
diff --git a/cinelerra-5.1/plugins/motion-cv/motion-cv.C b/cinelerra-5.1/plugins/motion-cv/motion-cv.C
new file mode 100644 (file)
index 0000000..9a70250
--- /dev/null
@@ -0,0 +1,2655 @@
+
+/*
+ * 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 "affine.h"
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "bchash.h"
+#include "bcsignals.h"
+#include "filexml.h"
+#include "keyframe.h"
+#include "language.h"
+#include "motion-cv.h"
+#include "motionwindow-cv.h"
+#include "mutex.h"
+#include "overlayframe.h"
+#include "rotateframe.h"
+#include "transportque.h"
+
+
+#include <errno.h>
+#include <unistd.h>
+
+REGISTER_PLUGIN(MotionCVMain)
+
+//#undef DEBUG
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+
+MotionCVConfig::MotionCVConfig()
+{
+       global_range_w = 5;
+       global_range_h = 5;
+       rotation_range = 5;
+       block_count = 1;
+       global_block_w = MIN_BLOCK;
+       global_block_h = MIN_BLOCK;
+       rotation_block_w = MIN_BLOCK;
+       rotation_block_h = MIN_BLOCK;
+       block_x = 50;
+       block_y = 50;
+       global_positions = 256;
+       rotate_positions = 4;
+       magnitude = 100;
+       return_speed = 0;
+       mode1 = STABILIZE;
+       global = 1;
+       rotate = 1;
+       addtrackedframeoffset = 0;
+       strcpy(tracking_file, TRACKING_FILE);
+       mode2 = RECALCULATE;
+       draw_vectors = 1;
+       mode3 = MotionCVConfig::TRACK_SINGLE;
+       track_frame = 0;
+       bottom_is_master = 1;
+       horizontal_only = 0;
+       vertical_only = 0;
+}
+
+void MotionCVConfig::boundaries()
+{
+       CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS);
+       CLAMP(global_range_h, MIN_RADIUS, MAX_RADIUS);
+       CLAMP(rotation_range, MIN_ROTATION, MAX_ROTATION);
+       CLAMP(block_count, MIN_BLOCKS, MAX_BLOCKS);
+       CLAMP(global_block_w, MIN_BLOCK, MAX_BLOCK);
+       CLAMP(global_block_h, MIN_BLOCK, MAX_BLOCK);
+       CLAMP(rotation_block_w, MIN_BLOCK, MAX_BLOCK);
+       CLAMP(rotation_block_h, MIN_BLOCK, MAX_BLOCK);
+}
+
+int MotionCVConfig::equivalent(MotionCVConfig &that)
+{
+       return global_range_w == that.global_range_w &&
+               global_range_h == that.global_range_h &&
+               rotation_range == that.rotation_range &&
+               mode1 == that.mode1 &&
+               global == that.global &&
+               rotate == that.rotate &&
+               addtrackedframeoffset == that.addtrackedframeoffset &&
+               !strcmp(tracking_file, that.tracking_file) &&
+               draw_vectors == that.draw_vectors &&
+               block_count == that.block_count &&
+               global_block_w == that.global_block_w &&
+               global_block_h == that.global_block_h &&
+               rotation_block_w == that.rotation_block_w &&
+               rotation_block_h == that.rotation_block_h &&
+               EQUIV(block_x, that.block_x) &&
+               EQUIV(block_y, that.block_y) &&
+               global_positions == that.global_positions &&
+               rotate_positions == that.rotate_positions &&
+               magnitude == that.magnitude &&
+               return_speed == that.return_speed &&
+               mode3 == that.mode3 &&
+               track_frame == that.track_frame &&
+               bottom_is_master == that.bottom_is_master &&
+               horizontal_only == that.horizontal_only &&
+               vertical_only == that.vertical_only;
+}
+
+void MotionCVConfig::copy_from(MotionCVConfig &that)
+{
+       global_range_w = that.global_range_w;
+       global_range_h = that.global_range_h;
+       rotation_range = that.rotation_range;
+       mode1 = that.mode1;
+       global = that.global;
+       rotate = that.rotate;
+       addtrackedframeoffset = that.addtrackedframeoffset;
+       strcpy(tracking_file, that.tracking_file);
+       mode2 = that.mode2;
+       draw_vectors = that.draw_vectors;
+       block_count = that.block_count;
+       block_x = that.block_x;
+       block_y = that.block_y;
+       global_positions = that.global_positions;
+       rotate_positions = that.rotate_positions;
+       global_block_w = that.global_block_w;
+       global_block_h = that.global_block_h;
+       rotation_block_w = that.rotation_block_w;
+       rotation_block_h = that.rotation_block_h;
+       magnitude = that.magnitude;
+       return_speed = that.return_speed;
+       mode3 = that.mode3;
+       track_frame = that.track_frame;
+       bottom_is_master = that.bottom_is_master;
+       horizontal_only = that.horizontal_only;
+       vertical_only = that.vertical_only;
+}
+
+void MotionCVConfig::interpolate(MotionCVConfig &prev, MotionCVConfig &next, 
+               int64_t prev_frame, int64_t next_frame, int64_t current_frame)
+{
+       copy_from(prev);
+}
+
+MotionCVMain::MotionCVMain(PluginServer *server)
+ : PluginVClient(server)
+{
+       engine = 0;
+       rotate_engine = 0;
+       motion_rotate = 0;
+       total_dx = 0;
+       total_dy = 0;
+       total_angle = 0;
+       overlayer = 0;
+       search_area = 0;
+       search_size = 0;
+       temp_frame = 0;
+       previous_frame_number = -1;
+
+       prev_global_ref = 0;
+       current_global_ref = 0;
+       global_target_src = 0;
+       global_target_dst = 0;
+
+       active_fp = 0;
+       active_file[0] = 0;
+       tracking_frame = -1;
+       dx_offset = dy_offset = 0;
+       save_dx = load_dx = 0;
+       save_dy = load_dy = 0;
+       save_dt = load_dt = 0;
+
+       prev_rotate_ref = 0;
+       current_rotate_ref = 0;
+       rotate_target_src = 0;
+       rotate_target_dst = 0;
+}
+
+MotionCVMain::~MotionCVMain()
+{
+
+       delete engine;
+       delete overlayer;
+       delete [] search_area;
+       delete temp_frame;
+       delete rotate_engine;
+       delete motion_rotate;
+
+       delete prev_global_ref;
+       delete current_global_ref;
+       delete global_target_src;
+       delete global_target_dst;
+
+       if( active_fp ) fclose(active_fp); 
+
+       delete prev_rotate_ref;
+       delete current_rotate_ref;
+       delete rotate_target_src;
+       delete rotate_target_dst;
+}
+
+const char* MotionCVMain::plugin_title() { return _("MotionCV"); }
+int MotionCVMain::is_realtime() { return 1; }
+int MotionCVMain::is_multichannel() { return 1; }
+
+
+NEW_WINDOW_MACRO(MotionCVMain, MotionCVWindow)
+
+LOAD_CONFIGURATION_MACRO(MotionCVMain, MotionCVConfig)
+
+
+
+void MotionCVMain::update_gui()
+{
+       if(thread)
+       {
+               if(load_configuration())
+               {
+                       thread->window->lock_window("MotionCVMain::update_gui");
+                       MotionCVWindow *window = (MotionCVWindow *)thread->window;
+                       
+                       char string[BCTEXTLEN];
+                       sprintf(string, "%d", config.global_positions);
+                       window->global_search_positions->set_text(string);
+                       sprintf(string, "%d", config.rotate_positions);
+                       window->rotation_search_positions->set_text(string);
+
+                       window->global_block_w->update(config.global_block_w);
+                       window->global_block_h->update(config.global_block_h);
+                       window->rotation_block_w->update(config.rotation_block_w);
+                       window->rotation_block_h->update(config.rotation_block_h);
+                       window->block_x->update(config.block_x);
+                       window->block_y->update(config.block_y);
+                       window->block_x_text->update((float)config.block_x);
+                       window->block_y_text->update((float)config.block_y);
+                       window->magnitude->update(config.magnitude);
+                       window->return_speed->update(config.return_speed);
+
+
+                       window->track_single->update(config.mode3 == MotionCVConfig::TRACK_SINGLE);
+                       window->track_frame_number->update(config.track_frame);
+                       window->track_previous->update(config.mode3 == MotionCVConfig::TRACK_PREVIOUS);
+                       window->previous_same->update(config.mode3 == MotionCVConfig::PREVIOUS_SAME_BLOCK);
+                       if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+                               window->track_frame_number->disable();
+                       else
+                               window->track_frame_number->enable();
+
+                       window->mode1->set_text(
+                               Mode1::to_text(config.mode1));
+                       window->mode2->set_text(
+                               Mode2::to_text(config.mode2));
+                       window->mode3->set_text(
+                               Mode3::to_text(config.horizontal_only, config.vertical_only));
+                       window->master_layer->set_text(
+                               MasterLayer::to_text(config.bottom_is_master));
+
+
+                       window->update_mode();
+                       window->unlock_window();
+               }
+       }
+}
+
+
+
+
+void MotionCVMain::save_data(KeyFrame *keyframe)
+{
+       FileXML output;
+
+// cause data to be stored directly in text
+       output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+       output.tag.set_title("MOTION");
+
+       output.tag.set_property("BLOCK_COUNT", config.block_count);
+       output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
+       output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
+       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("ROTATION_BLOCK_W", config.rotation_block_w);
+       output.tag.set_property("ROTATION_BLOCK_H", config.rotation_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("ROTATION_RANGE", config.rotation_range);
+       output.tag.set_property("MAGNITUDE", config.magnitude);
+       output.tag.set_property("RETURN_SPEED", config.return_speed);
+       output.tag.set_property("MODE1", config.mode1);
+       output.tag.set_property("GLOBAL", config.global);
+       output.tag.set_property("ROTATE", config.rotate);
+       output.tag.set_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
+       output.tag.set_property("TRACKING_FILE", config.tracking_file);
+       output.tag.set_property("MODE2", config.mode2);
+       output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
+       output.tag.set_property("MODE3", config.mode3);
+       output.tag.set_property("TRACK_FRAME", config.track_frame);
+       output.tag.set_property("BOTTOM_IS_MASTER", config.bottom_is_master);
+       output.tag.set_property("HORIZONTAL_ONLY", config.horizontal_only);
+       output.tag.set_property("VERTICAL_ONLY", config.vertical_only);
+       output.append_tag();
+       output.tag.set_title("/MOTION");
+       output.append_tag();
+       output.terminate_string();
+}
+
+void MotionCVMain::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+
+       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+
+       int result = 0;
+
+       while(!result)
+       {
+               result = input.read_tag();
+
+               if(!result)
+               {
+                       if(input.tag.title_is("MOTION"))
+                       {
+                               config.block_count = input.tag.get_property("BLOCK_COUNT", config.block_count);
+                               config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
+                               config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
+                               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.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
+                               config.rotation_block_h = input.tag.get_property("ROTATION_BLOCK_H", config.rotation_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.rotation_range = input.tag.get_property("ROTATION_RANGE", config.rotation_range);
+                               config.magnitude = input.tag.get_property("MAGNITUDE", config.magnitude);
+                               config.return_speed = input.tag.get_property("RETURN_SPEED", config.return_speed);
+                               config.mode1 = input.tag.get_property("MODE1", config.mode1);
+                               config.global = input.tag.get_property("GLOBAL", config.global);
+                               config.rotate = input.tag.get_property("ROTATE", config.rotate);
+                               config.addtrackedframeoffset = input.tag.get_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
+                               input.tag.get_property("TRACKING_FILE", config.tracking_file);
+                               config.mode2 = input.tag.get_property("MODE2", config.mode2);
+                               config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
+                               config.mode3 = input.tag.get_property("MODE3", config.mode3);
+                               config.track_frame = input.tag.get_property("TRACK_FRAME", config.track_frame);
+                               config.bottom_is_master = input.tag.get_property("BOTTOM_IS_MASTER", config.bottom_is_master);
+                               config.horizontal_only = input.tag.get_property("HORIZONTAL_ONLY", config.horizontal_only);
+                               config.vertical_only = input.tag.get_property("VERTICAL_ONLY", config.vertical_only);
+                       }
+               }
+       }
+       config.boundaries();
+}
+
+
+
+
+
+
+
+
+
+void MotionCVMain::allocate_temp(int w, int h, int color_model)
+{
+       if(temp_frame && 
+               (temp_frame->get_w() != w ||
+               temp_frame->get_h() != h))
+       {
+               delete temp_frame;
+               temp_frame = 0;
+       }
+       if(!temp_frame)
+               temp_frame = new VFrame(w, h, color_model);
+}
+
+
+
+void MotionCVMain::process_global()
+{
+       if(!engine) engine = new MotionCVScan(this,
+               PluginClient::get_project_smp() + 1,
+               PluginClient::get_project_smp() + 1);
+
+// Get the current motion vector between the previous and current frame
+       engine->scan_frame(current_global_ref, prev_global_ref);
+       current_dx = engine->dx_result;
+       current_dy = engine->dy_result;
+
+// Add current motion vector to accumulation vector.
+       if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+       {
+// Retract over time
+               total_dx = (int64_t)total_dx * (100 - config.return_speed) / 100;
+               total_dy = (int64_t)total_dy * (100 - config.return_speed) / 100;
+               total_dx += engine->dx_result;
+               total_dy += engine->dy_result;
+       }
+       else
+// Make accumulation vector current
+       {
+               total_dx = engine->dx_result;
+               total_dy = engine->dy_result;
+       }
+
+// Clamp accumulation vector
+       if(config.magnitude < 100)
+       {
+               //int block_w = (int64_t)config.global_block_w * 
+               //              current_global_ref->get_w() / 100;
+               //int block_h = (int64_t)config.global_block_h * 
+               //              current_global_ref->get_h() / 100;
+               int block_x_orig = (int64_t)(config.block_x * 
+                       current_global_ref->get_w() / 
+                       100);
+               int block_y_orig = (int64_t)(config.block_y *
+                       current_global_ref->get_h() / 
+                       100);
+
+               int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
+                       OVERSAMPLE * 
+                       config.magnitude / 
+                       100;
+               int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
+                       OVERSAMPLE *
+                       config.magnitude / 
+                       100;
+               int min_block_x = (int64_t)-block_x_orig * 
+                       OVERSAMPLE * 
+                       config.magnitude / 
+                       100;
+               int min_block_y = (int64_t)-block_y_orig * 
+                       OVERSAMPLE * 
+                       config.magnitude / 
+                       100;
+
+               CLAMP(total_dx, min_block_x, max_block_x);
+               CLAMP(total_dy, min_block_y, max_block_y);
+       }
+
+#ifdef DEBUG
+printf("MotionCVMain::process_global 2 total_dx=%.02f total_dy=%.02f\n", 
+(float)total_dx / OVERSAMPLE,
+(float)total_dy / OVERSAMPLE);
+#endif
+
+       if(config.mode3 != MotionCVConfig::TRACK_SINGLE && !config.rotate)
+       {
+// Transfer current reference frame to previous reference frame and update
+// counter.  Must wait for rotate to compare.
+               prev_global_ref->copy_from(current_global_ref);
+               previous_frame_number = get_source_position();
+       }
+
+// Decide what to do with target based on requested operation
+       int interpolation = NEAREST_NEIGHBOR;
+       float dx = 0;
+       float dy = 0;
+       switch(config.mode1)
+       {
+               case MotionCVConfig::NOTHING:
+                       global_target_dst->copy_from(global_target_src);
+                       break;
+               case MotionCVConfig::TRACK_PIXEL:
+                       interpolation = NEAREST_NEIGHBOR;
+                       dx = (int)(total_dx / OVERSAMPLE);
+                       dy = (int)(total_dy / OVERSAMPLE);
+                       break;
+               case MotionCVConfig::STABILIZE_PIXEL:
+                       interpolation = NEAREST_NEIGHBOR;
+                       dx = -(int)(total_dx / OVERSAMPLE);
+                       dy = -(int)(total_dy / OVERSAMPLE);
+                       break;
+                       break;
+               case MotionCVConfig::TRACK:
+                       interpolation = CUBIC_LINEAR;
+                       dx = (float)total_dx / OVERSAMPLE;
+                       dy = (float)total_dy / OVERSAMPLE;
+                       break;
+               case MotionCVConfig::STABILIZE:
+                       interpolation = CUBIC_LINEAR;
+                       dx = -(float)total_dx / OVERSAMPLE;
+                       dy = -(float)total_dy / OVERSAMPLE;
+                       break;
+       }
+
+
+       if(config.mode1 != MotionCVConfig::NOTHING)
+       {
+               if(!overlayer) 
+                       overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
+               global_target_dst->clear_frame();
+               overlayer->overlay(global_target_dst,
+                       global_target_src,
+                       0,
+                       0,
+                       global_target_src->get_w(),
+                       global_target_src->get_h(),
+                       dx,
+                       dy,
+                       (float)global_target_src->get_w() + dx,
+                       (float)global_target_src->get_h() + dy,
+                       1,
+                       TRANSFER_REPLACE,
+                       interpolation);
+       }
+}
+
+
+
+void MotionCVMain::process_rotation()
+{
+       int block_x;
+       int block_y;
+
+// Convert the previous global reference into the previous rotation reference.
+// Convert global target destination into rotation target source.
+       if(config.global)
+       {
+               if(!overlayer) 
+                       overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
+               float dx;
+               float dy;
+               if(config.mode3 == MotionCVConfig::TRACK_SINGLE)
+               {
+                       dx = (float)total_dx / OVERSAMPLE;
+                       dy = (float)total_dy / OVERSAMPLE;
+               }
+               else
+               {
+                       dx = (float)current_dx / OVERSAMPLE;
+                       dy = (float)current_dy / OVERSAMPLE;
+               }
+
+               prev_rotate_ref->clear_frame();
+               overlayer->overlay(prev_rotate_ref,
+                       prev_global_ref,
+                       0,
+                       0,
+                       prev_global_ref->get_w(),
+                       prev_global_ref->get_h(),
+                       dx,
+                       dy,
+                       (float)prev_global_ref->get_w() + dx,
+                       (float)prev_global_ref->get_h() + dy,
+                       1,
+                       TRANSFER_REPLACE,
+                       CUBIC_LINEAR);
+// Pivot is destination global position
+               block_x = (int)(prev_rotate_ref->get_w() * 
+                       config.block_x / 
+                       100 +
+                       (float)total_dx / 
+                       OVERSAMPLE);
+               block_y = (int)(prev_rotate_ref->get_h() * 
+                       config.block_y / 
+                       100 +
+                       (float)total_dy / 
+                       OVERSAMPLE);
+// Use the global target output as the rotation target input
+               rotate_target_src->copy_from(global_target_dst);
+// Transfer current reference frame to previous reference frame for global.
+               if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+               {
+                       prev_global_ref->copy_from(current_global_ref);
+                       previous_frame_number = get_source_position();
+               }
+       }
+       else
+       {
+// Pivot is fixed
+               block_x = (int)(prev_rotate_ref->get_w() * 
+                       config.block_x / 
+                       100);
+               block_y = (int)(prev_rotate_ref->get_h() * 
+                       config.block_y / 
+                       100);
+       }
+
+
+
+// Get rotation
+       if(!motion_rotate)
+               motion_rotate = new RotateCVScan(this, 
+                       get_project_smp() + 1, 
+                       get_project_smp() + 1);
+
+       current_angle = motion_rotate->scan_frame(prev_rotate_ref, 
+               current_rotate_ref,
+               block_x,
+               block_y);
+
+
+
+// Add current rotation to accumulation
+       if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+       {
+// Retract over time
+               total_angle = total_angle * (100 - config.return_speed) / 100;
+               total_angle += current_angle;
+
+               if(!config.global)
+               {
+// Transfer current reference frame to previous reference frame and update
+// counter.
+                       prev_rotate_ref->copy_from(current_rotate_ref);
+                       previous_frame_number = get_source_position();
+               }
+       }
+       else
+       {
+               total_angle = current_angle;
+       }
+
+#ifdef DEBUG
+printf("MotionCVMain::process_rotation total_angle=%f\n", total_angle);
+#endif
+
+
+// Calculate rotation parameters based on requested operation
+       float angle = 0;
+       switch(config.mode1)
+       {
+               case MotionCVConfig::NOTHING:
+                       rotate_target_dst->copy_from(rotate_target_src);
+                       break;
+               case MotionCVConfig::TRACK:
+               case MotionCVConfig::TRACK_PIXEL:
+                       angle = total_angle;
+                       break;
+               case MotionCVConfig::STABILIZE:
+               case MotionCVConfig::STABILIZE_PIXEL:
+                       angle = -total_angle;
+                       break;
+       }
+
+
+
+       if(config.mode1 != MotionCVConfig::NOTHING)
+       {
+               if(!rotate_engine)
+                       rotate_engine = new AffineEngine(PluginClient::get_project_smp() + 1,
+                               PluginClient::get_project_smp() + 1);
+
+               rotate_target_dst->clear_frame();
+
+// Determine pivot based on a number of factors.
+               switch(config.mode1)
+               {
+                       case MotionCVConfig::TRACK:
+                       case MotionCVConfig::TRACK_PIXEL:
+// Use destination of global tracking.
+                               rotate_engine->set_pivot(block_x, block_y);
+                               break;
+
+                       case MotionCVConfig::STABILIZE:
+                       case MotionCVConfig::STABILIZE_PIXEL:
+                               if(config.global)
+                               {
+// Use origin of global stabilize operation
+                                       rotate_engine->set_pivot((int)(rotate_target_dst->get_w() * 
+                                                       config.block_x / 
+                                                       100),
+                                               (int)(rotate_target_dst->get_h() * 
+                                                       config.block_y / 
+                                                       100));
+                               
+                               }
+                               else
+                               {
+// Use origin
+                                       rotate_engine->set_pivot(block_x, block_y);
+                               }
+                               break;
+               }
+
+
+               rotate_engine->rotate(rotate_target_dst, rotate_target_src, angle);
+// overlayer->overlay(rotate_target_dst,
+//     prev_rotate_ref,
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     1,
+//     TRANSFER_NORMAL,
+//     CUBIC_LINEAR);
+// overlayer->overlay(rotate_target_dst,
+//     current_rotate_ref,
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     1,
+//     TRANSFER_NORMAL,
+//     CUBIC_LINEAR);
+
+
+       }
+
+
+}
+
+
+
+
+
+
+
+
+
+int MotionCVMain::process_buffer(VFrame **frame,
+       int64_t start_position,
+       double frame_rate)
+{
+       int prev_config_mode2 = config.mode2;
+       int need_reconfigure = load_configuration();
+       int color_model = frame[0]->get_color_model();
+       w = frame[0]->get_w();
+       h = frame[0]->get_h();
+       
+
+#ifdef DEBUG
+printf("MotionCVMain::process_buffer 1 start_position=%jd\n", start_position);
+#endif
+
+
+// Calculate the source and destination pointers for each of the operations.
+// Get the layer to track motion in.
+       reference_layer = config.bottom_is_master ?
+               PluginClient::total_in_buffers - 1 :
+               0;
+// Get the layer to apply motion in.
+       target_layer = config.bottom_is_master ?
+               0 :
+               PluginClient::total_in_buffers - 1;
+
+
+       output_frame = frame[target_layer];
+
+
+// Get the position of previous reference frame.
+       int64_t actual_previous_number;
+// Skip if match frame not available
+       int skip_current = 0;
+
+
+       if(config.mode3 == MotionCVConfig::TRACK_SINGLE)
+       {
+               actual_previous_number = config.track_frame;
+               if(get_direction() == PLAY_REVERSE)
+                       actual_previous_number++;
+               if(actual_previous_number == start_position)
+                       skip_current = 1;
+       }
+       else
+       {
+               actual_previous_number = start_position;
+               if(get_direction() == PLAY_FORWARD)
+               {
+                       actual_previous_number--;
+                       if(actual_previous_number < get_source_start())
+                               skip_current = 1;
+                       else
+                       {
+                               KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
+                               if(keyframe->position > 0 &&
+                                       actual_previous_number < keyframe->position)
+                                       skip_current = 1;
+                       }
+               }
+               else
+               {
+                       actual_previous_number++;
+                       if(actual_previous_number >= get_source_start() + get_total_len())
+                               skip_current = 1;
+                       else
+                       {
+                               KeyFrame *keyframe = get_next_keyframe(start_position, 1);
+                               if(keyframe->position > 0 &&
+                                       actual_previous_number >= keyframe->position)
+                                       skip_current = 1;
+                       }
+               }
+
+// Only count motion since last keyframe
+               
+
+       }
+
+
+       if(!config.global && !config.rotate) skip_current = 1;
+
+
+
+
+// printf("process_realtime %d %lld %lld\n", 
+// skip_current, 
+// previous_frame_number, 
+// actual_previous_number);
+// Load match frame and reset vectors
+       int need_reload = !skip_current && 
+               (previous_frame_number != actual_previous_number ||
+               need_reconfigure);
+       if(need_reload)
+       {
+               total_dx = 0;
+               total_dy = 0;
+               total_angle = 0;
+               previous_frame_number = actual_previous_number;
+       }
+       if( prev_config_mode2 != MotionCVConfig::SAVE &&
+           config.mode2 == MotionCVConfig::SAVE ) {
+#ifdef DEBUG
+printf("MotionCVMain::process_buffer 2 remove tracking file: %s\n", config.tracking_file);
+#endif
+               ::remove(config.tracking_file);
+       }
+
+
+       if(skip_current)
+       {
+               total_dx = 0;
+               total_dy = 0;
+               current_dx = 0;
+               current_dy = 0;
+               total_angle = 0;
+               current_angle = 0;
+       }
+
+
+
+
+// Get the global pointers.  Here we walk through the sequence of events.
+       if(config.global)
+       {
+// Assume global only.  Global reads previous frame and compares
+// with current frame to get the current translation.
+// The center of the search area is fixed in compensate mode or
+// the user value + the accumulation vector in track mode.
+               if(!prev_global_ref)
+                       prev_global_ref = new VFrame(w, h, color_model);
+               if(!current_global_ref)
+                       current_global_ref = new VFrame(w, h, color_model);
+
+// Global loads the current target frame into the src and 
+// writes it to the dst frame with desired translation.
+               if(!global_target_src)
+                       global_target_src = new VFrame(w, h, color_model);
+               if(!global_target_dst)
+                       global_target_dst = new VFrame(w, h, color_model);
+
+
+// Load the global frames
+               if(need_reload)
+               {
+                       read_frame(prev_global_ref, 
+                               reference_layer, 
+                               previous_frame_number, 
+                               frame_rate,
+                               0);
+               }
+
+               read_frame(current_global_ref, 
+                       reference_layer, 
+                       start_position, 
+                       frame_rate,
+                       0);
+               read_frame(global_target_src,
+                       target_layer,
+                       start_position,
+                       frame_rate,
+                       0);
+
+
+
+// Global followed by rotate
+               if(config.rotate)
+               {
+// Must translate the previous global reference by the current global
+// accumulation vector to match the current global reference.
+// The center of the search area is always the user value + the accumulation
+// vector.
+                       if(!prev_rotate_ref)
+                               prev_rotate_ref = new VFrame(w, h, color_model);
+// The current global reference is the current rotation reference.
+                       if(!current_rotate_ref)
+                               current_rotate_ref = new VFrame(w, h, color_model);
+                       current_rotate_ref->copy_from(current_global_ref);
+
+// The global target destination is copied to the rotation target source
+// then written to the rotation output with rotation.
+// The pivot for the rotation is the center of the search area 
+// if we're tracking.
+// The pivot is fixed to the user position if we're compensating.
+                       if(!rotate_target_src)
+                               rotate_target_src = new VFrame(w, h, color_model);
+                       if(!rotate_target_dst)
+                               rotate_target_dst = new VFrame(w,h , color_model);
+               }
+       }
+       else
+// Rotation only
+       if(config.rotate)
+       {
+// Rotation reads the previous reference frame and compares it with current 
+// reference frame.
+               if(!prev_rotate_ref)
+                       prev_rotate_ref = new VFrame(w, h, color_model);
+               if(!current_rotate_ref)
+                       current_rotate_ref = new VFrame(w, h, color_model);
+
+// Rotation loads target frame to temporary, rotates it, and writes it to the
+// target frame.  The pivot is always fixed.
+               if(!rotate_target_src)
+                       rotate_target_src = new VFrame(w, h, color_model);
+               if(!rotate_target_dst)
+                       rotate_target_dst = new VFrame(w,h , color_model);
+
+
+// Load the rotate frames
+               if(need_reload)
+               {
+                       read_frame(prev_rotate_ref, 
+                               reference_layer, 
+                               previous_frame_number, 
+                               frame_rate,
+                               0);
+               }
+               read_frame(current_rotate_ref, 
+                       reference_layer, 
+                       start_position, 
+                       frame_rate,
+                       0);
+               read_frame(rotate_target_src,
+                       target_layer,
+                       start_position,
+                       frame_rate,
+                       0);
+       }
+
+       if(!skip_current)
+       {
+
+               if( config.mode2 == MotionCVConfig::LOAD ) {
+                       char line[BCTEXTLEN];
+                       int64_t frame_no, no;  int dx, dy;  float dt;
+                       if( config.addtrackedframeoffset && config.track_frame != tracking_frame ) {
+                               tracking_frame = frame_no = config.track_frame;
+                               if( !get_line_key(config.tracking_file, frame_no, line, sizeof(line)) &&
+                                   sscanf(line, "%jd %d %d %f", &no, &dx, &dy, &dt) == 4 ) {
+                                       dx_offset = dx;  dy_offset = dy;
+                               }
+                               else {
+#ifdef DEBUG
+                                       printf("MotionCVMain::process_buffer: no offset data frame %jd\n", frame_no);
+#endif
+                               }
+                       }
+// Load result from disk
+                       frame_no = get_source_position();
+                       if( !get_line_key(config.tracking_file, frame_no, line, sizeof(line)) &&
+                           sscanf(line, "%jd %d %d %f", &frame_no, &dx, &dy, &dt) == 4 ) {
+                               load_dx = dx;  load_dy = dy;  load_dt = dt;
+                       }
+                       else {
+#ifdef DEBUG
+                               printf("MotionCVMain::process_buffer: no tracking data frame %jd\n", frame_no);
+#endif
+                       }
+               }
+
+// Get position change from previous frame to current frame
+               if(config.global) process_global();
+// Get rotation change from previous frame to current frame
+               if(config.rotate) process_rotation();
+//frame[target_layer]->copy_from(prev_rotate_ref);
+//frame[target_layer]->copy_from(current_rotate_ref);
+
+// write results to disk
+               if( config.mode2 == MotionCVConfig::SAVE ) {
+                       FILE *output = fopen(config.tracking_file, "aw");
+                       if( output ) {
+                               int64_t frame_no = get_source_position();
+                               fprintf(output, "%jd %d %d %f\n", frame_no, save_dx, save_dy, save_dt);
+                               fclose(output);
+                       }
+                       else {
+                               perror("MotionCVMain::process buffer save");
+                       }
+               }
+       }
+
+
+// Transfer the relevant target frame to the output
+       if(!skip_current)
+       {
+               if(config.rotate)
+               {
+                       frame[target_layer]->copy_from(rotate_target_dst);
+               }
+               else
+               {
+                       frame[target_layer]->copy_from(global_target_dst);
+               }
+       }
+       else
+// Read the target destination directly
+       {
+               read_frame(frame[target_layer],
+                       target_layer,
+                       start_position,
+                       frame_rate,
+                       0);
+       }
+
+       if(config.draw_vectors)
+       {
+               draw_vectors(frame[target_layer]);
+       }
+
+#ifdef DEBUG
+printf("MotionCVMain::process_buffer 100\n");
+#endif
+       return 0;
+}
+
+
+void MotionCVMain::clamp_scan(int w, 
+       int h, 
+       int *block_x1,
+       int *block_y1,
+       int *block_x2,
+       int *block_y2,
+       int *scan_x1,
+       int *scan_y1,
+       int *scan_x2,
+       int *scan_y2,
+       int use_absolute)
+{
+// printf("MotionCVMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w,
+// h,
+// *block_x1,
+// *block_y1,
+// *block_x2,
+// *block_y2,
+// *scan_x1,
+// *scan_y1,
+// *scan_x2,
+// *scan_y2,
+// use_absolute);
+
+       if(use_absolute)
+       {
+// scan is always out of range before block.
+               if(*scan_x1 < 0)
+               {
+                       int difference = -*scan_x1;
+                       *block_x1 += difference;
+                       *scan_x1 = 0;
+               }
+
+               if(*scan_y1 < 0)
+               {
+                       int difference = -*scan_y1;
+                       *block_y1 += difference;
+                       *scan_y1 = 0;
+               }
+
+               if(*scan_x2 > w)
+               {
+                       int difference = *scan_x2 - w;
+                       *block_x2 -= difference;
+                       *scan_x2 -= difference;
+               }
+
+               if(*scan_y2 > h)
+               {
+                       int difference = *scan_y2 - h;
+                       *block_y2 -= difference;
+                       *scan_y2 -= difference;
+               }
+
+               CLAMP(*scan_x1, 0, w);
+               CLAMP(*scan_y1, 0, h);
+               CLAMP(*scan_x2, 0, w);
+               CLAMP(*scan_y2, 0, h);
+       }
+       else
+       {
+               if(*scan_x1 < 0)
+               {
+                       int difference = -*scan_x1;
+                       *block_x1 += difference;
+                       *scan_x2 += difference;
+                       *scan_x1 = 0;
+               }
+
+               if(*scan_y1 < 0)
+               {
+                       int difference = -*scan_y1;
+                       *block_y1 += difference;
+                       *scan_y2 += difference;
+                       *scan_y1 = 0;
+               }
+
+               if(*scan_x2 - *block_x1 + *block_x2 > w)
+               {
+                       int difference = *scan_x2 - *block_x1 + *block_x2 - w;
+                       *block_x2 -= difference;
+               }
+
+               if(*scan_y2 - *block_y1 + *block_y2 > h)
+               {
+                       int difference = *scan_y2 - *block_y1 + *block_y2 - h;
+                       *block_y2 -= difference;
+               }
+
+//             CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
+//             CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
+//             CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
+//             CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
+       }
+
+// Sanity checks which break the calculation but should never happen if the
+// center of the block is inside the frame.
+       CLAMP(*block_x1, 0, w);
+       CLAMP(*block_x2, 0, w);
+       CLAMP(*block_y1, 0, h);
+       CLAMP(*block_y2, 0, h);
+
+// printf("MotionCVMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w,
+// h,
+// *block_x1,
+// *block_y1,
+// *block_x2,
+// *block_y2,
+// *scan_x1,
+// *scan_y1,
+// *scan_x2,
+// *scan_y2,
+// use_absolute);
+}
+
+
+
+void MotionCVMain::draw_vectors(VFrame *frame)
+{
+       int w = frame->get_w();
+       int h = frame->get_h();
+       int global_x1, global_y1;
+       int global_x2, global_y2;
+       int block_x, block_y;
+       int block_w, block_h;
+       int block_x1, block_y1;
+       int block_x2, block_y2;
+       int block_x3, block_y3;
+       int block_x4, block_y4;
+       int search_w, search_h;
+       int search_x1, search_y1;
+       int search_x2, search_y2;
+       //int search_x3, search_y3;
+       //int search_x4, search_y4;
+
+       if(config.global)
+       {
+// Get vector
+// Start of vector is center of previous block.
+// End of vector is total accumulation.
+               if(config.mode3 == MotionCVConfig::TRACK_SINGLE)
+               {
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
+                               100);
+                       global_y1 = (int64_t)(config.block_y *
+                               h / 
+                               100);
+                       global_x2 = global_x1 + total_dx / OVERSAMPLE;
+                       global_y2 = global_y1 + total_dy / OVERSAMPLE;
+//printf("MotionCVMain::draw_vectors %d %d %d %d %d %d\n", total_dx, total_dy, global_x1, global_y1, global_x2, global_y2);
+               }
+               else
+// Start of vector is center of previous block.
+// End of vector is current change.
+               if(config.mode3 == MotionCVConfig::PREVIOUS_SAME_BLOCK)
+               {
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
+                               100);
+                       global_y1 = (int64_t)(config.block_y *
+                               h / 
+                               100);
+                       global_x2 = global_x1 + current_dx / OVERSAMPLE;
+                       global_y2 = global_y1 + current_dy / OVERSAMPLE;
+               }
+               else
+               {
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
+                               100 + 
+                               (total_dx - current_dx) / 
+                               OVERSAMPLE);
+                       global_y1 = (int64_t)(config.block_y *
+                               h / 
+                               100 +
+                               (total_dy - current_dy) /
+                               OVERSAMPLE);
+                       global_x2 = (int64_t)(config.block_x * 
+                               w / 
+                               100 + 
+                               total_dx / 
+                               OVERSAMPLE);
+                       global_y2 = (int64_t)(config.block_y *
+                               h / 
+                               100 +
+                               total_dy /
+                               OVERSAMPLE);
+               }
+
+               block_x = global_x1;
+               block_y = global_y1;
+               block_w = config.global_block_w * w / 100;
+               block_h = config.global_block_h * h / 100;
+               block_x1 = block_x - block_w / 2;
+               block_y1 = block_y - block_h / 2;
+               block_x2 = block_x + block_w / 2;
+               block_y2 = block_y + block_h / 2;
+               search_w = config.global_range_w * w / 100;
+               search_h = config.global_range_h * h / 100;
+               search_x1 = block_x1 - search_w / 2;
+               search_y1 = block_y1 - search_h / 2;
+               search_x2 = block_x2 + search_w / 2;
+               search_y2 = block_y2 + search_h / 2;
+
+// printf("MotionCVMain::draw_vectors %d %d %d %d %d %d %d %d %d %d %d %d\n",
+// global_x1,
+// global_y1,
+// block_w,
+// block_h,
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// search_x1,
+// search_y1,
+// search_x2,
+// search_y2);
+
+               clamp_scan(w, 
+                       h, 
+                       &block_x1,
+                       &block_y1,
+                       &block_x2,
+                       &block_y2,
+                       &search_x1,
+                       &search_y1,
+                       &search_x2,
+                       &search_y2,
+                       1);
+
+// Vector
+               draw_arrow(frame, global_x1, global_y1, global_x2, global_y2);
+
+// Macroblock
+               draw_line(frame, block_x1, block_y1, block_x2, block_y1);
+               draw_line(frame, block_x2, block_y1, block_x2, block_y2);
+               draw_line(frame, block_x2, block_y2, block_x1, block_y2);
+               draw_line(frame, block_x1, block_y2, block_x1, block_y1);
+
+
+// Search area
+               draw_line(frame, search_x1, search_y1, search_x2, search_y1);
+               draw_line(frame, search_x2, search_y1, search_x2, search_y2);
+               draw_line(frame, search_x2, search_y2, search_x1, search_y2);
+               draw_line(frame, search_x1, search_y2, search_x1, search_y1);
+
+// Block should be endpoint of motion
+               if(config.rotate)
+               {
+                       block_x = global_x2;
+                       block_y = global_y2;
+               }
+       }
+       else
+       {
+               block_x = (int64_t)(config.block_x * w / 100);
+               block_y = (int64_t)(config.block_y * h / 100);
+       }
+
+       block_w = config.rotation_block_w * w / 100;
+       block_h = config.rotation_block_h * h / 100;
+       if(config.rotate)
+       {
+               float angle = total_angle * 2 * M_PI / 360;
+               double base_angle1 = atan((float)block_h / block_w);
+               double base_angle2 = atan((float)block_w / block_h);
+               double target_angle1 = base_angle1 + angle;
+               double target_angle2 = base_angle2 + angle;
+               double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
+               block_x1 = (int)(block_x - cos(target_angle1) * radius);
+               block_y1 = (int)(block_y - sin(target_angle1) * radius);
+               block_x2 = (int)(block_x + sin(target_angle2) * radius);
+               block_y2 = (int)(block_y - cos(target_angle2) * radius);
+               block_x3 = (int)(block_x - sin(target_angle2) * radius);
+               block_y3 = (int)(block_y + cos(target_angle2) * radius);
+               block_x4 = (int)(block_x + cos(target_angle1) * radius);
+               block_y4 = (int)(block_y + sin(target_angle1) * radius);
+
+               draw_line(frame, block_x1, block_y1, block_x2, block_y2);
+               draw_line(frame, block_x2, block_y2, block_x4, block_y4);
+               draw_line(frame, block_x4, block_y4, block_x3, block_y3);
+               draw_line(frame, block_x3, block_y3, block_x1, block_y1);
+
+
+// Center
+               if(!config.global)
+               {
+                       draw_line(frame, block_x, block_y - 5, block_x, block_y + 6);
+                       draw_line(frame, block_x - 5, block_y, block_x + 6, block_y);
+               }
+       }
+}
+
+
+
+void MotionCVMain::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 MotionCVMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
+{
+       int w = labs(x2 - x1);
+       int h = labs(y2 - y1);
+//printf("MotionCVMain::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("MotionCVMain::draw_line 2\n");
+}
+
+#define ARROW_SIZE 10
+void MotionCVMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
+{
+       double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
+       double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
+       double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
+       int x3;
+       int y3;
+       int x4;
+       int y4;
+       if(x2 < x1)
+       {
+               x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
+               y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
+               x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
+               y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
+       }
+       else
+       {
+               x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
+               y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
+               x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
+               y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
+       }
+
+// Main vector
+       draw_line(frame, x1, y1, x2, y2);
+//     draw_line(frame, x1, y1 + 1, x2, y2 + 1);
+
+// Arrow line
+       if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
+//     draw_line(frame, x2, y2 + 1, x3, y3 + 1);
+// Arrow line
+       if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
+//     draw_line(frame, x2, y2 + 1, x4, y4 + 1);
+}
+
+
+
+
+#define ABS_DIFF(type, temp_type, multiplier, components) \
+{ \
+       temp_type result_temp = 0; \
+       for(int i = 0; i < h; i++) \
+       { \
+               type *prev_row = (type*)prev_ptr; \
+               type *current_row = (type*)current_ptr; \
+               for(int j = 0; j < w; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               temp_type difference; \
+                               difference = *prev_row++ - *current_row++; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
+                       } \
+                       if(components == 4) \
+                       { \
+                               prev_row++; \
+                               current_row++; \
+                       } \
+               } \
+               prev_ptr += row_bytes; \
+               current_ptr += row_bytes; \
+       } \
+       result = (int64_t)(result_temp * multiplier); \
+}
+
+int64_t MotionCVMain::abs_diff(unsigned char *prev_ptr,
+       unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model)
+{
+       int64_t result = 0;
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       ABS_DIFF(float, double, 0x10000, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       ABS_DIFF(float, double, 0x10000, 4)
+                       break;
+               case BC_YUV888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_YUV161616:
+                       ABS_DIFF(uint16_t, int64_t, 1, 3)
+                       break;
+               case BC_YUVA16161616:
+                       ABS_DIFF(uint16_t, int64_t, 1, 4)
+                       break;
+       }
+       return result;
+}
+
+
+
+#define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
+{ \
+       temp_type result_temp = 0; \
+       temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
+       temp_type y1_fraction = 0x100 - y2_fraction; \
+       temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
+       temp_type x1_fraction = 0x100 - x2_fraction; \
+       for(int i = 0; i < h_sub; i++) \
+       { \
+               type *prev_row1 = (type*)prev_ptr; \
+               type *prev_row2 = (type*)prev_ptr + components; \
+               type *prev_row3 = (type*)(prev_ptr + row_bytes); \
+               type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
+               type *current_row = (type*)current_ptr; \
+               for(int j = 0; j < w_sub; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               temp_type difference; \
+                               temp_type prev_value = \
+                                       (*prev_row1++ * x1_fraction * y1_fraction + \
+                                       *prev_row2++ * x2_fraction * y1_fraction + \
+                                       *prev_row3++ * x1_fraction * y2_fraction + \
+                                       *prev_row4++ * x2_fraction * y2_fraction) / \
+                                       0x100 / 0x100; \
+                               temp_type current_value = *current_row++; \
+                               difference = prev_value - current_value; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
+                       } \
+ \
+                       if(components == 4) \
+                       { \
+                               prev_row1++; \
+                               prev_row2++; \
+                               prev_row3++; \
+                               prev_row4++; \
+                               current_row++; \
+                       } \
+               } \
+               prev_ptr += row_bytes; \
+               current_ptr += row_bytes; \
+       } \
+       result = (int64_t)(result_temp * multiplier); \
+}
+
+
+
+
+int64_t MotionCVMain::abs_diff_sub(unsigned char *prev_ptr,
+       unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model,
+       int sub_x,
+       int sub_y)
+{
+       int h_sub = h - 1;
+       int w_sub = w - 1;
+       int64_t result = 0;
+
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       ABS_DIFF_SUB(float, double, 0x10000, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       ABS_DIFF_SUB(float, double, 0x10000, 4)
+                       break;
+               case BC_YUV888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_YUV161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
+                       break;
+               case BC_YUVA16161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
+                       break;
+       }
+       return result;
+}
+
+int MotionCVMain::get_line_key(const char *filename, int64_t key, char *line, int len)
+{
+       if( active_fp && strcmp(active_file, filename) ) {
+               fclose(active_fp);  active_fp = 0;  active_file[0] = 0;
+       }
+       if( !active_fp ) {
+               if( !(active_fp = fopen(filename, "r")) ) {
+                       perror("open motion file");
+                       fprintf(stderr,"err reading key %jd\n", key);
+                       return -1;
+               }
+               strcpy(active_file, filename);
+               tracking_frame = -1;
+       }
+       int64_t recd = 0;
+       if( fgets(line, len, active_fp) && (recd=strtol(line,0,0)) == key )
+               return 0;
+// binary search file
+       fseek(active_fp, 0, SEEK_END);
+       int64_t l = -1, r = ftell(active_fp);
+       while( (r-l) > 1 ) {
+               int64_t m = (l+r) / 2;
+               fseek(active_fp, m, SEEK_SET);
+               if( m > 0 && !fgets(line, len, active_fp) ) {
+                       fprintf(stderr,"err reading key %jd\n", key);
+                       return -1;
+               }
+               if( fgets(line, len, active_fp) ) {
+                       recd = strtol(line,0,0);
+                       if( recd == key ) return 0;
+                       if( recd < key ) { l = m; continue; }
+               }
+               r = m;
+       }
+       return 1;
+}
+
+
+
+MotionCVScanPackage::MotionCVScanPackage()
+ : LoadPackage()
+{
+       valid = 1;
+}
+
+
+MotionCVScanUnit::MotionCVScanUnit(MotionCVScan *server, 
+       MotionCVMain *plugin)
+ : LoadClient(server)
+{
+       this->plugin = plugin;
+       this->server = server;
+       cache_lock = new Mutex("MotionCVScanUnit::cache_lock");
+}
+
+MotionCVScanUnit::~MotionCVScanUnit()
+{
+       delete cache_lock;
+}
+
+
+
+void MotionCVScanUnit::process_package(LoadPackage *package)
+{
+       MotionCVScanPackage *pkg = (MotionCVScanPackage*)package;
+       //int w = server->current_frame->get_w();
+       //int h = server->current_frame->get_h();
+       int color_model = server->current_frame->get_color_model();
+       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+       int row_bytes = server->current_frame->get_bytes_per_line();
+
+// Single pixel
+       if(!server->subpixel)
+       {
+               int search_x = pkg->scan_x1 + (pkg->pixel % (pkg->scan_x2 - pkg->scan_x1));
+               int search_y = pkg->scan_y1 + (pkg->pixel / (pkg->scan_x2 - pkg->scan_x1));
+
+// Try cache
+               pkg->difference1 = server->get_cache(search_x, search_y);
+               if(pkg->difference1 < 0)
+               {
+//printf("MotionCVScanUnit::process_package 1 %d %d\n", 
+//search_x, search_y, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1);
+// Pointers to first pixel in each block
+                       unsigned char *prev_ptr = server->previous_frame->get_rows()[
+                               search_y] +     
+                               search_x * pixel_size;
+                       unsigned char *current_ptr = server->current_frame->get_rows()[
+                               pkg->block_y1] +
+                               pkg->block_x1 * pixel_size;
+// Scan block
+                       pkg->difference1 = plugin->abs_diff(prev_ptr,
+                               current_ptr,
+                               row_bytes,
+                               pkg->block_x2 - pkg->block_x1,
+                               pkg->block_y2 - pkg->block_y1,
+                               color_model);
+//printf("MotionCVScanUnit::process_package 2\n");
+                       server->put_cache(search_x, search_y, pkg->difference1);
+               }
+       }
+       else
+// Sub pixel
+       {
+               int sub_x = pkg->pixel % (OVERSAMPLE * 2 - 1) + 1;
+               int sub_y = pkg->pixel / (OVERSAMPLE * 2 - 1) + 1;
+
+               if(plugin->config.horizontal_only)
+               {
+                       sub_y = 0;
+               }
+
+               if(plugin->config.vertical_only)
+               {
+                       sub_x = 0;
+               }
+
+               int search_x = pkg->scan_x1 + sub_x / OVERSAMPLE;
+               int search_y = pkg->scan_y1 + sub_y / OVERSAMPLE;
+               sub_x %= OVERSAMPLE;
+               sub_y %= OVERSAMPLE;
+
+
+               unsigned char *prev_ptr = server->previous_frame->get_rows()[
+                       search_y] +
+                       search_x * pixel_size;
+               unsigned char *current_ptr = server->current_frame->get_rows()[
+                       pkg->block_y1] +
+                       pkg->block_x1 * pixel_size;
+
+// With subpixel, there are two ways to compare each position, one by shifting
+// the previous frame and two by shifting the current frame.
+               pkg->difference1 = plugin->abs_diff_sub(prev_ptr,
+                       current_ptr,
+                       row_bytes,
+                       pkg->block_x2 - pkg->block_x1,
+                       pkg->block_y2 - pkg->block_y1,
+                       color_model,
+                       sub_x,
+                       sub_y);
+               pkg->difference2 = plugin->abs_diff_sub(current_ptr,
+                       prev_ptr,
+                       row_bytes,
+                       pkg->block_x2 - pkg->block_x1,
+                       pkg->block_y2 - pkg->block_y1,
+                       color_model,
+                       sub_x,
+                       sub_y);
+// printf("MotionCVScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
+// sub_x,
+// sub_y,
+// search_x,
+// search_y,
+// pkg->difference1,
+// pkg->difference2);
+       }
+
+
+
+
+}
+
+
+
+
+
+
+
+
+
+
+int64_t MotionCVScanUnit::get_cache(int x, int y)
+{
+       int64_t result = -1;
+       cache_lock->lock("MotionCVScanUnit::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               MotionCVScanCache *ptr = cache.values[i];
+               if(ptr->x == x && ptr->y == y)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void MotionCVScanUnit::put_cache(int x, int y, int64_t difference)
+{
+       MotionCVScanCache *ptr = new MotionCVScanCache(x, y, difference);
+       cache_lock->lock("MotionCVScanUnit::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+
+
+
+
+
+
+MotionCVScan::MotionCVScan(MotionCVMain *plugin, 
+       int total_clients,
+       int total_packages)
+ : LoadServer(
+//1, 1 
+total_clients, total_packages 
+)
+{
+       this->plugin = plugin;
+       cache_lock = new Mutex("MotionCVScan::cache_lock");
+}
+
+MotionCVScan::~MotionCVScan()
+{
+       delete cache_lock;
+}
+
+
+void MotionCVScan::init_packages()
+{
+// Set package coords
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               MotionCVScanPackage *pkg = (MotionCVScanPackage*)get_package(i);
+
+               pkg->block_x1 = block_x1;
+               pkg->block_x2 = block_x2;
+               pkg->block_y1 = block_y1;
+               pkg->block_y2 = block_y2;
+               pkg->scan_x1 = scan_x1;
+               pkg->scan_x2 = scan_x2;
+               pkg->scan_y1 = scan_y1;
+               pkg->scan_y2 = scan_y2;
+               pkg->pixel = (int64_t)i * (int64_t)total_pixels / (int64_t)total_steps;
+               pkg->difference1 = 0;
+               pkg->difference2 = 0;
+               pkg->dx = 0;
+               pkg->dy = 0;
+               pkg->valid = 1;
+       }
+}
+
+LoadClient* MotionCVScan::new_client()
+{
+       return new MotionCVScanUnit(this, plugin);
+}
+
+LoadPackage* MotionCVScan::new_package()
+{
+       return new MotionCVScanPackage;
+}
+
+
+void MotionCVScan::scan_frame(VFrame *previous_frame,
+       VFrame *current_frame)
+{
+       this->previous_frame = previous_frame;
+       this->current_frame = current_frame;
+       subpixel = 0;
+
+       cache.remove_all_objects();
+
+
+// Single macroblock
+       int w = current_frame->get_w();
+       int h = current_frame->get_h();
+
+// Initial search parameters
+       int scan_w = w * plugin->config.global_range_w / 100;
+       int scan_h = h * plugin->config.global_range_h / 100;
+       int block_w = w * plugin->config.global_block_w / 100;
+       int block_h = h * plugin->config.global_block_h / 100;
+
+// Location of block in previous frame
+       block_x1 = (int)(w * plugin->config.block_x / 100 - block_w / 2);
+       block_y1 = (int)(h * plugin->config.block_y / 100 - block_h / 2);
+       block_x2 = (int)(w * plugin->config.block_x / 100 + block_w / 2);
+       block_y2 = (int)(h * plugin->config.block_y / 100 + block_h / 2);
+
+// Offset to location of previous block.  This offset needn't be very accurate
+// since it's the offset of the previous image and current image we want.
+       if(plugin->config.mode3 == MotionCVConfig::TRACK_PREVIOUS)
+       {
+               block_x1 += plugin->total_dx / OVERSAMPLE;
+               block_y1 += plugin->total_dy / OVERSAMPLE;
+               block_x2 += plugin->total_dx / OVERSAMPLE;
+               block_y2 += plugin->total_dy / OVERSAMPLE;
+       }
+
+       skip = 0;
+
+       switch(plugin->config.mode2)
+       {
+// Don't calculate
+               case MotionCVConfig::NO_CALCULATE:
+                       dx_result = 0;
+                       dy_result = 0;
+                       skip = 1;
+                       break;
+
+               case MotionCVConfig::LOAD:
+               {
+                       dx_result = plugin->load_dx;
+                       dy_result = plugin->load_dy;
+                       skip = 1;
+                       break;
+               }
+
+// Scan from scratch
+               default:
+                       skip = 0;
+                       break;
+       }
+
+// Perform scan
+       if(!skip)
+       {
+// Location of block in current frame
+               int x_result = block_x1;
+               int y_result = block_y1;
+
+// printf("MotionCVScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
+// block_x1 + block_w / 2,
+// block_y1 + block_h / 2,
+// block_w,
+// block_h,
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2);
+
+               while(1)
+               {
+                       scan_x1 = x_result - scan_w / 2;
+                       scan_y1 = y_result - scan_h / 2;
+                       scan_x2 = x_result + scan_w / 2;
+                       scan_y2 = y_result + scan_h / 2;
+
+
+
+// Zero out requested values
+                       if(plugin->config.horizontal_only)
+                       {
+                               scan_y1 = block_y1;
+                               scan_y2 = block_y1 + 1;
+                       }
+                       if(plugin->config.vertical_only)
+                       {
+                               scan_x1 = block_x1;
+                               scan_x2 = block_x1 + 1;
+                       }
+
+// printf("MotionCVScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// scan_x1,
+// scan_y1,
+// scan_x2,
+// scan_y2);
+// Clamp the block coords before the scan so we get useful scan coords.
+                       MotionCVMain::clamp_scan(w, 
+                               h, 
+                               &block_x1,
+                               &block_y1,
+                               &block_x2,
+                               &block_y2,
+                               &scan_x1,
+                               &scan_y1,
+                               &scan_x2,
+                               &scan_y2,
+                               0);
+// printf("MotionCVScan::scan_frame 1\n    block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n    scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n    x_result=%d y_result=%d\n", 
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// scan_x1, 
+// scan_y1, 
+// scan_x2, 
+// scan_y2, 
+// x_result, 
+// y_result);
+
+
+// Give up if invalid coords.
+                       if(scan_y2 <= scan_y1 ||
+                               scan_x2 <= scan_x1 ||
+                               block_x2 <= block_x1 ||
+                               block_y2 <= block_y1)
+                               break;
+
+// For subpixel, the top row and left column are skipped
+                       if(subpixel)
+                       {
+                               if(plugin->config.horizontal_only ||
+                                       plugin->config.vertical_only)
+                               {
+                                       total_pixels = 4 * OVERSAMPLE * OVERSAMPLE - 4 * OVERSAMPLE;
+                               }
+                               else
+                               {
+                                       total_pixels = 4 * OVERSAMPLE;
+                               }
+
+                               total_steps = total_pixels;
+
+                               set_package_count(total_steps);
+                               process_packages();
+
+// Get least difference
+                               int64_t min_difference = -1;
+                               for(int i = 0; i < get_total_packages(); i++)
+                               {
+                                       MotionCVScanPackage *pkg = (MotionCVScanPackage*)get_package(i);
+                                       if(pkg->difference1 < min_difference || min_difference == -1)
+                                       {
+                                               min_difference = pkg->difference1;
+
+                                               if(plugin->config.vertical_only)
+                                                       x_result = scan_x1 * OVERSAMPLE;
+                                               else
+                                                       x_result = scan_x1 * OVERSAMPLE + 
+                                                               (pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1;
+                                               
+                                               if(plugin->config.horizontal_only)
+                                                       y_result = scan_y1 * OVERSAMPLE;
+                                               else
+                                                       y_result = scan_y1 * OVERSAMPLE + 
+                                                               (pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1;
+
+
+// Fill in results
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+                                       }
+
+                                       if(pkg->difference2 < min_difference)
+                                       {
+                                               min_difference = pkg->difference2;
+
+                                               if(plugin->config.vertical_only)
+                                                       x_result = scan_x1 * OVERSAMPLE;
+                                               else
+                                                       x_result = scan_x2 * OVERSAMPLE -
+                                                               ((pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1);
+
+                                               if(plugin->config.horizontal_only)
+                                                       y_result = scan_y1 * OVERSAMPLE;
+                                               else
+                                                       y_result = scan_y2 * OVERSAMPLE -
+                                                               ((pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1);
+
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+                                       }
+                               }
+
+//printf("MotionCVScan::scan_frame 1 %d %d %d %d\n", block_x1, block_y1, x_result, y_result);
+                               break;
+                       }
+                       else
+                       {
+                               total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
+                               total_steps = MIN(plugin->config.global_positions, total_pixels);
+
+                               set_package_count(total_steps);
+                               process_packages();
+
+// Get least difference
+                               int64_t min_difference = -1;
+                               for(int i = 0; i < get_total_packages(); i++)
+                               {
+                                       MotionCVScanPackage *pkg = (MotionCVScanPackage*)get_package(i);
+                                       if(pkg->difference1 < min_difference || min_difference == -1)
+                                       {
+                                               min_difference = pkg->difference1;
+                                               x_result = scan_x1 + (pkg->pixel % (scan_x2 - scan_x1));
+                                               y_result = scan_y1 + (pkg->pixel / (scan_x2 - scan_x1));
+                                               x_result *= OVERSAMPLE;
+                                               y_result *= OVERSAMPLE;
+                                       }
+                               }
+
+// printf("MotionCVScan::scan_frame 10 total_steps=%d total_pixels=%d subpixel=%d\n",
+// total_steps, 
+// total_pixels,
+// subpixel);
+// 
+// printf("    scan w=%d h=%d scan x1=%d y1=%d x2=%d y2=%d\n",
+// scan_w,
+// scan_h, 
+// scan_x1,
+// scan_y1,
+// scan_x2,
+// scan_y2);
+// 
+// printf("MotionCVScan::scan_frame 2 block x1=%d y1=%d x2=%d y2=%d result x=%.2f y=%.2f\n", 
+// block_x1, 
+// block_y1, 
+// block_x2,
+// block_y2,
+// (float)x_result / 4, 
+// (float)y_result / 4);
+
+
+// If a new search is required, rescale results back to pixels.
+                               if(total_steps >= total_pixels)
+                               {
+// Single pixel accuracy reached.  Now do exhaustive subpixel search.
+                                       if(plugin->config.mode1 == MotionCVConfig::STABILIZE ||
+                                               plugin->config.mode1 == MotionCVConfig::TRACK ||
+                                               plugin->config.mode1 == MotionCVConfig::NOTHING)
+                                       {
+                                               x_result /= OVERSAMPLE;
+                                               y_result /= OVERSAMPLE;
+                                               scan_w = 2;
+                                               scan_h = 2;
+                                               subpixel = 1;
+                                       }
+                                       else
+                                       {
+// Fill in results and quit
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+                                               break;
+                                       }
+                               }
+                               else
+// Reduce scan area and try again
+                               {
+                                       scan_w = (scan_x2 - scan_x1) / 2;
+                                       scan_h = (scan_y2 - scan_y1) / 2;
+                                       x_result /= OVERSAMPLE;
+                                       y_result /= OVERSAMPLE;
+                               }
+                       }
+               }
+
+               // Add offsets from the "tracked single frame"
+               dx_result = plugin->dx_offset - dx_result;
+               dy_result = plugin->dy_offset - dy_result;
+
+               if(plugin->config.mode2 == MotionCVConfig::SAVE)
+               {
+                       plugin->save_dx = dx_result;
+                       plugin->save_dy = dy_result;
+               }
+       }
+
+#ifdef DEBUG
+printf("MotionCVScan::scan_frame 10 dx=%.2f dy=%.2f\n", 
+(float)this->dx_result / OVERSAMPLE,
+(float)this->dy_result / OVERSAMPLE);
+#endif
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int64_t MotionCVScan::get_cache(int x, int y)
+{
+       int64_t result = -1;
+       cache_lock->lock("MotionCVScan::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               MotionCVScanCache *ptr = cache.values[i];
+               if(ptr->x == x && ptr->y == y)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void MotionCVScan::put_cache(int x, int y, int64_t difference)
+{
+       MotionCVScanCache *ptr = new MotionCVScanCache(x, y, difference);
+       cache_lock->lock("MotionCVScan::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+MotionCVScanCache::MotionCVScanCache(int x, int y, int64_t difference)
+{
+       this->x = x;
+       this->y = y;
+       this->difference = difference;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+RotateCVScanPackage::RotateCVScanPackage()
+{
+}
+
+
+RotateCVScanUnit::RotateCVScanUnit(RotateCVScan *server, MotionCVMain *plugin)
+ : LoadClient(server)
+{
+       this->server = server;
+       this->plugin = plugin;
+       rotater = 0;
+       temp = 0;
+}
+
+RotateCVScanUnit::~RotateCVScanUnit()
+{
+       delete rotater;
+       delete temp;
+}
+
+void RotateCVScanUnit::process_package(LoadPackage *package)
+{
+       if(server->skip) return;
+       RotateCVScanPackage *pkg = (RotateCVScanPackage*)package;
+
+       if((pkg->difference = server->get_cache(pkg->angle)) < 0)
+       {
+//printf("RotateCVScanUnit::process_package 1\n");
+               int color_model = server->previous_frame->get_color_model();
+               int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+               int row_bytes = server->previous_frame->get_bytes_per_line();
+
+               if(!rotater)
+                       rotater = new AffineEngine(1, 1);
+               if(!temp) temp = new VFrame(
+                       server->previous_frame->get_w(),
+                       server->previous_frame->get_h(),
+                       color_model);
+
+
+// RotateCV original block size
+               rotater->set_viewport(server->block_x1, 
+                       server->block_y1,
+                       server->block_x2 - server->block_x1,
+                       server->block_y2 - server->block_y1);
+               rotater->set_pivot(server->block_x, server->block_y);
+//pkg->angle = 2;
+               rotater->rotate(temp,
+                       server->previous_frame,
+                       pkg->angle);
+// Clamp coordinates
+               int x1 = server->scan_x;
+               int y1 = server->scan_y;
+               int x2 = x1 + server->scan_w;
+               int y2 = y1 + server->scan_h;
+               x2 = MIN(temp->get_w(), x2);
+               y2 = MIN(temp->get_h(), y2);
+               x2 = MIN(server->current_frame->get_w(), x2);
+               y2 = MIN(server->current_frame->get_h(), y2);
+               x1 = MAX(0, x1);
+               y1 = MAX(0, y1);
+
+               if(x2 > x1 && y2 > y1)
+               {
+                       pkg->difference = plugin->abs_diff(
+                               temp->get_rows()[y1] + x1 * pixel_size,
+                               server->current_frame->get_rows()[y1] + x1 * pixel_size,
+                               row_bytes,
+                               x2 - x1,
+                               y2 - y1,
+                               color_model);
+//printf("RotateCVScanUnit::process_package %d\n", __LINE__);
+                       server->put_cache(pkg->angle, pkg->difference);
+                }
+
+// printf("RotateCVScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%lld\n", 
+// server->block_x1, 
+// server->block_y1,
+// server->block_x2 - server->block_x1,
+// server->block_y2 - server->block_y1,
+// server->block_x,
+// server->block_y,
+// pkg->angle, 
+// server->scan_w,
+// server->scan_h,
+// pkg->difference);
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+RotateCVScan::RotateCVScan(MotionCVMain *plugin, 
+       int total_clients, 
+       int total_packages)
+ : LoadServer(
+//1, 1 
+total_clients, total_packages 
+)
+{
+       this->plugin = plugin;
+       cache_lock = new Mutex("RotateCVScan::cache_lock");
+}
+
+
+RotateCVScan::~RotateCVScan()
+{
+       delete cache_lock;
+}
+
+void RotateCVScan::init_packages()
+{
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               RotateCVScanPackage *pkg = (RotateCVScanPackage*)get_package(i);
+               pkg->angle = i * 
+                       (scan_angle2 - scan_angle1) / 
+                       (total_steps - 1) + 
+                       scan_angle1;
+       }
+}
+
+LoadClient* RotateCVScan::new_client()
+{
+       return new RotateCVScanUnit(this, plugin);
+}
+
+LoadPackage* RotateCVScan::new_package()
+{
+       return new RotateCVScanPackage;
+}
+
+
+float RotateCVScan::scan_frame(VFrame *previous_frame,
+       VFrame *current_frame,
+       int block_x,
+       int block_y)
+{
+       skip = 0;
+       this->block_x = block_x;
+       this->block_y = block_y;
+
+       switch(plugin->config.mode2)
+       {
+               case MotionCVConfig::NO_CALCULATE:
+                       result = 0;
+                       skip = 1;
+                       break;
+
+               case MotionCVConfig::LOAD:
+               {
+                       result = plugin->load_dt;
+                       skip = 1;
+                       break;
+               }
+       }
+
+
+       this->previous_frame = previous_frame;
+       this->current_frame = current_frame;
+       int w = current_frame->get_w();
+       int h = current_frame->get_h();
+       int block_w = w * plugin->config.rotation_block_w / 100;
+       int block_h = h * plugin->config.rotation_block_h / 100;
+
+       if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
+       if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
+       if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
+       if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
+
+       block_x1 = this->block_x - block_w / 2;
+       block_x2 = this->block_x + block_w / 2;
+       block_y1 = this->block_y - block_h / 2;
+       block_y2 = this->block_y + block_h / 2;
+
+
+// Calculate the maximum area available to scan after rotation.
+// Must be calculated from the starting range because of cache.
+// Get coords of rectangle after rotation.
+       double center_x = this->block_x;
+       double center_y = this->block_y;
+       double max_angle = plugin->config.rotation_range;
+       double base_angle1 = atan((float)block_h / block_w);
+       double base_angle2 = atan((float)block_w / block_h);
+       double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
+       double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
+       double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
+       double x1 = center_x - cos(target_angle1) * radius;
+       double y1 = center_y - sin(target_angle1) * radius;
+       double x2 = center_x + sin(target_angle2) * radius;
+       double y2 = center_y - cos(target_angle2) * radius;
+       double x3 = center_x - sin(target_angle2) * radius;
+       double y3 = center_y + cos(target_angle2) * radius;
+
+// Track top edge to find greatest area.
+       double max_area1 = 0;
+       //double max_x1 = 0;
+       double max_y1 = 0;
+       for(double x = x1; x < x2; x++)
+       {
+               double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+               if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area1)
+                       {
+                               max_area1 = area;
+                               //max_x1 = x;
+                               max_y1 = y;
+                       }
+               }
+       }
+
+// Track left edge to find greatest area.
+       double max_area2 = 0;
+       double max_x2 = 0;
+       //double max_y2 = 0;
+       for(double y = y1; y < y3; y++)
+       {
+               double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
+               if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area2)
+                       {
+                               max_area2 = area;
+                               max_x2 = x;
+                               //max_y2 = y;
+                       }
+               }
+       }
+
+       double max_x, max_y;
+       max_x = max_x2;
+       max_y = max_y1;
+
+// Get reduced scan coords
+       scan_w = (int)(fabs(max_x - center_x) * 2);
+       scan_h = (int)(fabs(max_y - center_y) * 2);
+       scan_x = (int)(center_x - scan_w / 2);
+       scan_y = (int)(center_y - scan_h / 2);
+// printf("RotateCVScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n", 
+// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
+// printf("    angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
+
+// Determine min angle from size of block
+       double angle1 = atan((double)block_h / block_w);
+       double angle2 = atan((double)(block_h - 1) / (block_w + 1));
+       double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
+       min_angle = MAX(min_angle, MIN_ANGLE);
+
+#ifdef DEBUG
+printf("RotateCVScan::scan_frame min_angle=%f\n", min_angle * 360 / 2 / M_PI);
+#endif
+
+       cache.remove_all_objects();
+       if(!skip)
+       {
+// Initial search range
+               float angle_range = (float)plugin->config.rotation_range;
+               result = 0;
+               total_steps = plugin->config.rotate_positions;
+
+
+               while(angle_range >= min_angle * total_steps)
+               {
+                       scan_angle1 = result - angle_range;
+                       scan_angle2 = result + angle_range;
+
+
+                       set_package_count(total_steps);
+//set_package_count(1);
+                       process_packages();
+
+                       int64_t min_difference = -1;
+                       for(int i = 0; i < get_total_packages(); i++)
+                       {
+                               RotateCVScanPackage *pkg = (RotateCVScanPackage*)get_package(i);
+                               if(pkg->difference < min_difference || min_difference == -1)
+                               {
+                                       min_difference = pkg->difference;
+                                       result = pkg->angle;
+                               }
+//break;
+                       }
+
+                       angle_range /= 2;
+
+//break;
+               }
+
+               if(plugin->config.mode2 == MotionCVConfig::SAVE) {
+                       plugin->save_dt = result;
+               }
+       }
+
+#ifdef DEBUG
+printf("RotateCVScan::scan_frame 10 angle=%f\n", result);
+#endif
+
+       return result;
+}
+
+int64_t RotateCVScan::get_cache(float angle)
+{
+       int64_t result = -1;
+       cache_lock->lock("RotateCVScan::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               RotateCVScanCache *ptr = cache.values[i];
+               if(fabs(ptr->angle - angle) <= MIN_ANGLE)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void RotateCVScan::put_cache(float angle, int64_t difference)
+{
+       RotateCVScanCache *ptr = new RotateCVScanCache(angle, difference);
+       cache_lock->lock("RotateCVScan::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+
+
+
+
+RotateCVScanCache::RotateCVScanCache(float angle, int64_t difference)
+{
+       this->angle = angle;
+       this->difference = difference;
+}
+
+
+
diff --git a/cinelerra-5.1/plugins/motion-cv/motion-cv.C.orig b/cinelerra-5.1/plugins/motion-cv/motion-cv.C.orig
new file mode 100644 (file)
index 0000000..a5eb191
--- /dev/null
@@ -0,0 +1,2731 @@
+
+/*
+ * 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 "affine.h"
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "bchash.h"
+#include "bcsignals.h"
+#include "filexml.h"
+#include "keyframe.h"
+#include "language.h"
+#include "motion-cv.h"
+#include "motionwindow-cv.h"
+#include "mutex.h"
+#include "overlayframe.h"
+#include "rotateframe.h"
+#include "transportque.h"
+
+
+#include <errno.h>
+#include <unistd.h>
+
+REGISTER_PLUGIN(MotionCVMain)
+
+//#undef DEBUG
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+
+MotionCVConfig::MotionCVConfig()
+{
+       global_range_w = 5;
+       global_range_h = 5;
+       rotation_range = 5;
+       block_count = 1;
+       global_block_w = MIN_BLOCK;
+       global_block_h = MIN_BLOCK;
+       rotation_block_w = MIN_BLOCK;
+       rotation_block_h = MIN_BLOCK;
+       block_x = 50;
+       block_y = 50;
+       global_positions = 256;
+       rotate_positions = 4;
+       magnitude = 100;
+       return_speed = 0;
+       mode1 = STABILIZE;
+       global = 1;
+       rotate = 1;
+       addtrackedframeoffset = 0;
+       mode2 = RECALCULATE;
+       draw_vectors = 1;
+       mode3 = MotionCVConfig::TRACK_SINGLE;
+       track_frame = 0;
+       bottom_is_master = 1;
+       horizontal_only = 0;
+       vertical_only = 0;
+}
+
+void MotionCVConfig::boundaries()
+{
+       CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS);
+       CLAMP(global_range_h, MIN_RADIUS, MAX_RADIUS);
+       CLAMP(rotation_range, MIN_ROTATION, MAX_ROTATION);
+       CLAMP(block_count, MIN_BLOCKS, MAX_BLOCKS);
+       CLAMP(global_block_w, MIN_BLOCK, MAX_BLOCK);
+       CLAMP(global_block_h, MIN_BLOCK, MAX_BLOCK);
+       CLAMP(rotation_block_w, MIN_BLOCK, MAX_BLOCK);
+       CLAMP(rotation_block_h, MIN_BLOCK, MAX_BLOCK);
+}
+
+int MotionCVConfig::equivalent(MotionCVConfig &that)
+{
+       return global_range_w == that.global_range_w &&
+               global_range_h == that.global_range_h &&
+               rotation_range == that.rotation_range &&
+               mode1 == that.mode1 &&
+               global == that.global &&
+               rotate == that.rotate &&
+               addtrackedframeoffset == that.addtrackedframeoffset &&
+               draw_vectors == that.draw_vectors &&
+               block_count == that.block_count &&
+               global_block_w == that.global_block_w &&
+               global_block_h == that.global_block_h &&
+               rotation_block_w == that.rotation_block_w &&
+               rotation_block_h == that.rotation_block_h &&
+               EQUIV(block_x, that.block_x) &&
+               EQUIV(block_y, that.block_y) &&
+               global_positions == that.global_positions &&
+               rotate_positions == that.rotate_positions &&
+               magnitude == that.magnitude &&
+               return_speed == that.return_speed &&
+               mode3 == that.mode3 &&
+               track_frame == that.track_frame &&
+               bottom_is_master == that.bottom_is_master &&
+               horizontal_only == that.horizontal_only &&
+               vertical_only == that.vertical_only;
+}
+
+void MotionCVConfig::copy_from(MotionCVConfig &that)
+{
+       global_range_w = that.global_range_w;
+       global_range_h = that.global_range_h;
+       rotation_range = that.rotation_range;
+       mode1 = that.mode1;
+       global = that.global;
+       rotate = that.rotate;
+       addtrackedframeoffset = that.addtrackedframeoffset;
+       mode2 = that.mode2;
+       draw_vectors = that.draw_vectors;
+       block_count = that.block_count;
+       block_x = that.block_x;
+       block_y = that.block_y;
+       global_positions = that.global_positions;
+       rotate_positions = that.rotate_positions;
+       global_block_w = that.global_block_w;
+       global_block_h = that.global_block_h;
+       rotation_block_w = that.rotation_block_w;
+       rotation_block_h = that.rotation_block_h;
+       magnitude = that.magnitude;
+       return_speed = that.return_speed;
+       mode3 = that.mode3;
+       track_frame = that.track_frame;
+       bottom_is_master = that.bottom_is_master;
+       horizontal_only = that.horizontal_only;
+       vertical_only = that.vertical_only;
+}
+
+void MotionCVConfig::interpolate(MotionCVConfig &prev, 
+       MotionCVConfig &next, 
+       int64_t prev_frame, 
+       int64_t next_frame, 
+       int64_t current_frame)
+{
+       //double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
+       //double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+       this->block_x = prev.block_x;
+       this->block_y = prev.block_y;
+       global_range_w = prev.global_range_w;
+       global_range_h = prev.global_range_h;
+       rotation_range = prev.rotation_range;
+       mode1 = prev.mode1;
+       global = prev.global;
+       rotate = prev.rotate;
+       addtrackedframeoffset = prev.addtrackedframeoffset;
+       mode2 = prev.mode2;
+       draw_vectors = prev.draw_vectors;
+       block_count = prev.block_count;
+       global_positions = prev.global_positions;
+       rotate_positions = prev.rotate_positions;
+       global_block_w = prev.global_block_w;
+       global_block_h = prev.global_block_h;
+       rotation_block_w = prev.rotation_block_w;
+       rotation_block_h = prev.rotation_block_h;
+       magnitude = prev.magnitude;
+       return_speed = prev.return_speed;
+       mode3 = prev.mode3;
+       track_frame = prev.track_frame;
+       bottom_is_master = prev.bottom_is_master;
+       horizontal_only = prev.horizontal_only;
+       vertical_only = prev.vertical_only;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+MotionCVMain::MotionCVMain(PluginServer *server)
+ : PluginVClient(server)
+{
+       engine = 0;
+       rotate_engine = 0;
+       motion_rotate = 0;
+       total_dx = 0;
+       total_dy = 0;
+       total_angle = 0;
+       overlayer = 0;
+       search_area = 0;
+       search_size = 0;
+       temp_frame = 0;
+       previous_frame_number = -1;
+
+       prev_global_ref = 0;
+       current_global_ref = 0;
+       global_target_src = 0;
+       global_target_dst = 0;
+
+       prev_rotate_ref = 0;
+       current_rotate_ref = 0;
+       rotate_target_src = 0;
+       rotate_target_dst = 0;
+}
+
+MotionCVMain::~MotionCVMain()
+{
+
+       delete engine;
+       delete overlayer;
+       delete [] search_area;
+       delete temp_frame;
+       delete rotate_engine;
+       delete motion_rotate;
+
+
+       delete prev_global_ref;
+       delete current_global_ref;
+       delete global_target_src;
+       delete global_target_dst;
+
+       delete prev_rotate_ref;
+       delete current_rotate_ref;
+       delete rotate_target_src;
+       delete rotate_target_dst;
+}
+
+const char* MotionCVMain::plugin_title() { return _("MotionCV"); }
+int MotionCVMain::is_realtime() { return 1; }
+int MotionCVMain::is_multichannel() { return 1; }
+
+
+NEW_WINDOW_MACRO(MotionCVMain, MotionCVWindow)
+
+LOAD_CONFIGURATION_MACRO(MotionCVMain, MotionCVConfig)
+
+
+
+void MotionCVMain::update_gui()
+{
+       if(thread)
+       {
+               if(load_configuration())
+               {
+                       thread->window->lock_window("MotionCVMain::update_gui");
+                       MotionCVWindow *window = (MotionCVWindow *)thread->window;
+                       
+                       char string[BCTEXTLEN];
+                       sprintf(string, "%d", config.global_positions);
+                       window->global_search_positions->set_text(string);
+                       sprintf(string, "%d", config.rotate_positions);
+                       window->rotation_search_positions->set_text(string);
+
+                       window->global_block_w->update(config.global_block_w);
+                       window->global_block_h->update(config.global_block_h);
+                       window->rotation_block_w->update(config.rotation_block_w);
+                       window->rotation_block_h->update(config.rotation_block_h);
+                       window->block_x->update(config.block_x);
+                       window->block_y->update(config.block_y);
+                       window->block_x_text->update((float)config.block_x);
+                       window->block_y_text->update((float)config.block_y);
+                       window->magnitude->update(config.magnitude);
+                       window->return_speed->update(config.return_speed);
+
+
+                       window->track_single->update(config.mode3 == MotionCVConfig::TRACK_SINGLE);
+                       window->track_frame_number->update(config.track_frame);
+                       window->track_previous->update(config.mode3 == MotionCVConfig::TRACK_PREVIOUS);
+                       window->previous_same->update(config.mode3 == MotionCVConfig::PREVIOUS_SAME_BLOCK);
+                       if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+                               window->track_frame_number->disable();
+                       else
+                               window->track_frame_number->enable();
+
+                       window->mode1->set_text(
+                               Mode1::to_text(config.mode1));
+                       window->mode2->set_text(
+                               Mode2::to_text(config.mode2));
+                       window->mode3->set_text(
+                               Mode3::to_text(config.horizontal_only, config.vertical_only));
+                       window->master_layer->set_text(
+                               MasterLayer::to_text(config.bottom_is_master));
+
+
+                       window->update_mode();
+                       window->unlock_window();
+               }
+       }
+}
+
+
+
+
+void MotionCVMain::save_data(KeyFrame *keyframe)
+{
+       FileXML output;
+
+// cause data to be stored directly in text
+       output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+       output.tag.set_title("MOTION");
+
+       output.tag.set_property("BLOCK_COUNT", config.block_count);
+       output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
+       output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
+       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("ROTATION_BLOCK_W", config.rotation_block_w);
+       output.tag.set_property("ROTATION_BLOCK_H", config.rotation_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("ROTATION_RANGE", config.rotation_range);
+       output.tag.set_property("MAGNITUDE", config.magnitude);
+       output.tag.set_property("RETURN_SPEED", config.return_speed);
+       output.tag.set_property("MODE1", config.mode1);
+       output.tag.set_property("GLOBAL", config.global);
+       output.tag.set_property("ROTATE", config.rotate);
+       output.tag.set_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
+       output.tag.set_property("MODE2", config.mode2);
+       output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
+       output.tag.set_property("MODE3", config.mode3);
+       output.tag.set_property("TRACK_FRAME", config.track_frame);
+       output.tag.set_property("BOTTOM_IS_MASTER", config.bottom_is_master);
+       output.tag.set_property("HORIZONTAL_ONLY", config.horizontal_only);
+       output.tag.set_property("VERTICAL_ONLY", config.vertical_only);
+       output.append_tag();
+       output.tag.set_title("/MOTION");
+       output.append_tag();
+       output.terminate_string();
+}
+
+void MotionCVMain::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+
+       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+
+       int result = 0;
+
+       while(!result)
+       {
+               result = input.read_tag();
+
+               if(!result)
+               {
+                       if(input.tag.title_is("MOTION"))
+                       {
+                               config.block_count = input.tag.get_property("BLOCK_COUNT", config.block_count);
+                               config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
+                               config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
+                               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.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
+                               config.rotation_block_h = input.tag.get_property("ROTATION_BLOCK_H", config.rotation_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.rotation_range = input.tag.get_property("ROTATION_RANGE", config.rotation_range);
+                               config.magnitude = input.tag.get_property("MAGNITUDE", config.magnitude);
+                               config.return_speed = input.tag.get_property("RETURN_SPEED", config.return_speed);
+                               config.mode1 = input.tag.get_property("MODE1", config.mode1);
+                               config.global = input.tag.get_property("GLOBAL", config.global);
+                               config.rotate = input.tag.get_property("ROTATE", config.rotate);
+                               config.addtrackedframeoffset = input.tag.get_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
+                               config.mode2 = input.tag.get_property("MODE2", config.mode2);
+                               config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
+                               config.mode3 = input.tag.get_property("MODE3", config.mode3);
+                               config.track_frame = input.tag.get_property("TRACK_FRAME", config.track_frame);
+                               config.bottom_is_master = input.tag.get_property("BOTTOM_IS_MASTER", config.bottom_is_master);
+                               config.horizontal_only = input.tag.get_property("HORIZONTAL_ONLY", config.horizontal_only);
+                               config.vertical_only = input.tag.get_property("VERTICAL_ONLY", config.vertical_only);
+                       }
+               }
+       }
+       config.boundaries();
+}
+
+
+
+
+
+
+
+
+
+void MotionCVMain::allocate_temp(int w, int h, int color_model)
+{
+       if(temp_frame && 
+               (temp_frame->get_w() != w ||
+               temp_frame->get_h() != h))
+       {
+               delete temp_frame;
+               temp_frame = 0;
+       }
+       if(!temp_frame)
+               temp_frame = new VFrame(w, h, color_model);
+}
+
+
+
+void MotionCVMain::process_global()
+{
+       if(!engine) engine = new MotionCVScan(this,
+               PluginClient::get_project_smp() + 1,
+               PluginClient::get_project_smp() + 1);
+
+// Get the current motion vector between the previous and current frame
+       engine->scan_frame(current_global_ref, prev_global_ref);
+       current_dx = engine->dx_result;
+       current_dy = engine->dy_result;
+
+// Add current motion vector to accumulation vector.
+       if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+       {
+// Retract over time
+               total_dx = (int64_t)total_dx * (100 - config.return_speed) / 100;
+               total_dy = (int64_t)total_dy * (100 - config.return_speed) / 100;
+               total_dx += engine->dx_result;
+               total_dy += engine->dy_result;
+       }
+       else
+// Make accumulation vector current
+       {
+               total_dx = engine->dx_result;
+               total_dy = engine->dy_result;
+       }
+
+// Clamp accumulation vector
+       if(config.magnitude < 100)
+       {
+               //int block_w = (int64_t)config.global_block_w * 
+               //              current_global_ref->get_w() / 100;
+               //int block_h = (int64_t)config.global_block_h * 
+               //              current_global_ref->get_h() / 100;
+               int block_x_orig = (int64_t)(config.block_x * 
+                       current_global_ref->get_w() / 
+                       100);
+               int block_y_orig = (int64_t)(config.block_y *
+                       current_global_ref->get_h() / 
+                       100);
+
+               int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
+                       OVERSAMPLE * 
+                       config.magnitude / 
+                       100;
+               int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
+                       OVERSAMPLE *
+                       config.magnitude / 
+                       100;
+               int min_block_x = (int64_t)-block_x_orig * 
+                       OVERSAMPLE * 
+                       config.magnitude / 
+                       100;
+               int min_block_y = (int64_t)-block_y_orig * 
+                       OVERSAMPLE * 
+                       config.magnitude / 
+                       100;
+
+               CLAMP(total_dx, min_block_x, max_block_x);
+               CLAMP(total_dy, min_block_y, max_block_y);
+       }
+
+#ifdef DEBUG
+printf("MotionCVMain::process_global 2 total_dx=%.02f total_dy=%.02f\n", 
+(float)total_dx / OVERSAMPLE,
+(float)total_dy / OVERSAMPLE);
+#endif
+
+       if(config.mode3 != MotionCVConfig::TRACK_SINGLE && !config.rotate)
+       {
+// Transfer current reference frame to previous reference frame and update
+// counter.  Must wait for rotate to compare.
+               prev_global_ref->copy_from(current_global_ref);
+               previous_frame_number = get_source_position();
+       }
+
+// Decide what to do with target based on requested operation
+       int interpolation = NEAREST_NEIGHBOR;
+       float dx = 0;
+       float dy = 0;
+       switch(config.mode1)
+       {
+               case MotionCVConfig::NOTHING:
+                       global_target_dst->copy_from(global_target_src);
+                       break;
+               case MotionCVConfig::TRACK_PIXEL:
+                       interpolation = NEAREST_NEIGHBOR;
+                       dx = (int)(total_dx / OVERSAMPLE);
+                       dy = (int)(total_dy / OVERSAMPLE);
+                       break;
+               case MotionCVConfig::STABILIZE_PIXEL:
+                       interpolation = NEAREST_NEIGHBOR;
+                       dx = -(int)(total_dx / OVERSAMPLE);
+                       dy = -(int)(total_dy / OVERSAMPLE);
+                       break;
+                       break;
+               case MotionCVConfig::TRACK:
+                       interpolation = CUBIC_LINEAR;
+                       dx = (float)total_dx / OVERSAMPLE;
+                       dy = (float)total_dy / OVERSAMPLE;
+                       break;
+               case MotionCVConfig::STABILIZE:
+                       interpolation = CUBIC_LINEAR;
+                       dx = -(float)total_dx / OVERSAMPLE;
+                       dy = -(float)total_dy / OVERSAMPLE;
+                       break;
+       }
+
+
+       if(config.mode1 != MotionCVConfig::NOTHING)
+       {
+               if(!overlayer) 
+                       overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
+               global_target_dst->clear_frame();
+               overlayer->overlay(global_target_dst,
+                       global_target_src,
+                       0,
+                       0,
+                       global_target_src->get_w(),
+                       global_target_src->get_h(),
+                       dx,
+                       dy,
+                       (float)global_target_src->get_w() + dx,
+                       (float)global_target_src->get_h() + dy,
+                       1,
+                       TRANSFER_REPLACE,
+                       interpolation);
+       }
+}
+
+
+
+void MotionCVMain::process_rotation()
+{
+       int block_x;
+       int block_y;
+
+// Convert the previous global reference into the previous rotation reference.
+// Convert global target destination into rotation target source.
+       if(config.global)
+       {
+               if(!overlayer) 
+                       overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
+               float dx;
+               float dy;
+               if(config.mode3 == MotionCVConfig::TRACK_SINGLE)
+               {
+                       dx = (float)total_dx / OVERSAMPLE;
+                       dy = (float)total_dy / OVERSAMPLE;
+               }
+               else
+               {
+                       dx = (float)current_dx / OVERSAMPLE;
+                       dy = (float)current_dy / OVERSAMPLE;
+               }
+
+               prev_rotate_ref->clear_frame();
+               overlayer->overlay(prev_rotate_ref,
+                       prev_global_ref,
+                       0,
+                       0,
+                       prev_global_ref->get_w(),
+                       prev_global_ref->get_h(),
+                       dx,
+                       dy,
+                       (float)prev_global_ref->get_w() + dx,
+                       (float)prev_global_ref->get_h() + dy,
+                       1,
+                       TRANSFER_REPLACE,
+                       CUBIC_LINEAR);
+// Pivot is destination global position
+               block_x = (int)(prev_rotate_ref->get_w() * 
+                       config.block_x / 
+                       100 +
+                       (float)total_dx / 
+                       OVERSAMPLE);
+               block_y = (int)(prev_rotate_ref->get_h() * 
+                       config.block_y / 
+                       100 +
+                       (float)total_dy / 
+                       OVERSAMPLE);
+// Use the global target output as the rotation target input
+               rotate_target_src->copy_from(global_target_dst);
+// Transfer current reference frame to previous reference frame for global.
+               if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+               {
+                       prev_global_ref->copy_from(current_global_ref);
+                       previous_frame_number = get_source_position();
+               }
+       }
+       else
+       {
+// Pivot is fixed
+               block_x = (int)(prev_rotate_ref->get_w() * 
+                       config.block_x / 
+                       100);
+               block_y = (int)(prev_rotate_ref->get_h() * 
+                       config.block_y / 
+                       100);
+       }
+
+
+
+// Get rotation
+       if(!motion_rotate)
+               motion_rotate = new RotateCVScan(this, 
+                       get_project_smp() + 1, 
+                       get_project_smp() + 1);
+
+       current_angle = motion_rotate->scan_frame(prev_rotate_ref, 
+               current_rotate_ref,
+               block_x,
+               block_y);
+
+
+
+// Add current rotation to accumulation
+       if(config.mode3 != MotionCVConfig::TRACK_SINGLE)
+       {
+// Retract over time
+               total_angle = total_angle * (100 - config.return_speed) / 100;
+               total_angle += current_angle;
+
+               if(!config.global)
+               {
+// Transfer current reference frame to previous reference frame and update
+// counter.
+                       prev_rotate_ref->copy_from(current_rotate_ref);
+                       previous_frame_number = get_source_position();
+               }
+       }
+       else
+       {
+               total_angle = current_angle;
+       }
+
+#ifdef DEBUG
+printf("MotionCVMain::process_rotation total_angle=%f\n", total_angle);
+#endif
+
+
+// Calculate rotation parameters based on requested operation
+       float angle = 0;
+       switch(config.mode1)
+       {
+               case MotionCVConfig::NOTHING:
+                       rotate_target_dst->copy_from(rotate_target_src);
+                       break;
+               case MotionCVConfig::TRACK:
+               case MotionCVConfig::TRACK_PIXEL:
+                       angle = total_angle;
+                       break;
+               case MotionCVConfig::STABILIZE:
+               case MotionCVConfig::STABILIZE_PIXEL:
+                       angle = -total_angle;
+                       break;
+       }
+
+
+
+       if(config.mode1 != MotionCVConfig::NOTHING)
+       {
+               if(!rotate_engine)
+                       rotate_engine = new AffineEngine(PluginClient::get_project_smp() + 1,
+                               PluginClient::get_project_smp() + 1);
+
+               rotate_target_dst->clear_frame();
+
+// Determine pivot based on a number of factors.
+               switch(config.mode1)
+               {
+                       case MotionCVConfig::TRACK:
+                       case MotionCVConfig::TRACK_PIXEL:
+// Use destination of global tracking.
+                               rotate_engine->set_pivot(block_x, block_y);
+                               break;
+
+                       case MotionCVConfig::STABILIZE:
+                       case MotionCVConfig::STABILIZE_PIXEL:
+                               if(config.global)
+                               {
+// Use origin of global stabilize operation
+                                       rotate_engine->set_pivot((int)(rotate_target_dst->get_w() * 
+                                                       config.block_x / 
+                                                       100),
+                                               (int)(rotate_target_dst->get_h() * 
+                                                       config.block_y / 
+                                                       100));
+                               
+                               }
+                               else
+                               {
+// Use origin
+                                       rotate_engine->set_pivot(block_x, block_y);
+                               }
+                               break;
+               }
+
+
+               rotate_engine->rotate(rotate_target_dst, rotate_target_src, angle);
+// overlayer->overlay(rotate_target_dst,
+//     prev_rotate_ref,
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     1,
+//     TRANSFER_NORMAL,
+//     CUBIC_LINEAR);
+// overlayer->overlay(rotate_target_dst,
+//     current_rotate_ref,
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     0,
+//     0,
+//     prev_rotate_ref->get_w(),
+//     prev_rotate_ref->get_h(),
+//     1,
+//     TRANSFER_NORMAL,
+//     CUBIC_LINEAR);
+
+
+       }
+
+
+}
+
+
+
+
+
+
+
+
+
+int MotionCVMain::process_buffer(VFrame **frame,
+       int64_t start_position,
+       double frame_rate)
+{
+       int need_reconfigure = load_configuration();
+       int color_model = frame[0]->get_color_model();
+       w = frame[0]->get_w();
+       h = frame[0]->get_h();
+       
+
+#ifdef DEBUG
+printf("MotionCVMain::process_buffer 1 start_position=%jd\n", start_position);
+#endif
+
+
+// Calculate the source and destination pointers for each of the operations.
+// Get the layer to track motion in.
+       reference_layer = config.bottom_is_master ?
+               PluginClient::total_in_buffers - 1 :
+               0;
+// Get the layer to apply motion in.
+       target_layer = config.bottom_is_master ?
+               0 :
+               PluginClient::total_in_buffers - 1;
+
+
+       output_frame = frame[target_layer];
+
+
+// Get the position of previous reference frame.
+       int64_t actual_previous_number;
+// Skip if match frame not available
+       int skip_current = 0;
+
+
+       if(config.mode3 == MotionCVConfig::TRACK_SINGLE)
+       {
+               actual_previous_number = config.track_frame;
+               if(get_direction() == PLAY_REVERSE)
+                       actual_previous_number++;
+               if(actual_previous_number == start_position)
+                       skip_current = 1;
+       }
+       else
+       {
+               actual_previous_number = start_position;
+               if(get_direction() == PLAY_FORWARD)
+               {
+                       actual_previous_number--;
+                       if(actual_previous_number < get_source_start())
+                               skip_current = 1;
+                       else
+                       {
+                               KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
+                               if(keyframe->position > 0 &&
+                                       actual_previous_number < keyframe->position)
+                                       skip_current = 1;
+                       }
+               }
+               else
+               {
+                       actual_previous_number++;
+                       if(actual_previous_number >= get_source_start() + get_total_len())
+                               skip_current = 1;
+                       else
+                       {
+                               KeyFrame *keyframe = get_next_keyframe(start_position, 1);
+                               if(keyframe->position > 0 &&
+                                       actual_previous_number >= keyframe->position)
+                                       skip_current = 1;
+                       }
+               }
+
+// Only count motion since last keyframe
+               
+
+       }
+
+
+       if(!config.global && !config.rotate) skip_current = 1;
+
+
+
+
+// printf("process_realtime %d %lld %lld\n", 
+// skip_current, 
+// previous_frame_number, 
+// actual_previous_number);
+// Load match frame and reset vectors
+       int need_reload = !skip_current && 
+               (previous_frame_number != actual_previous_number ||
+               need_reconfigure);
+       if(need_reload)
+       {
+               total_dx = 0;
+               total_dy = 0;
+               total_angle = 0;
+               previous_frame_number = actual_previous_number;
+       }
+
+
+       if(skip_current)
+       {
+               total_dx = 0;
+               total_dy = 0;
+               current_dx = 0;
+               current_dy = 0;
+               total_angle = 0;
+               current_angle = 0;
+       }
+
+
+
+
+// Get the global pointers.  Here we walk through the sequence of events.
+       if(config.global)
+       {
+// Assume global only.  Global reads previous frame and compares
+// with current frame to get the current translation.
+// The center of the search area is fixed in compensate mode or
+// the user value + the accumulation vector in track mode.
+               if(!prev_global_ref)
+                       prev_global_ref = new VFrame(w, h, color_model);
+               if(!current_global_ref)
+                       current_global_ref = new VFrame(w, h, color_model);
+
+// Global loads the current target frame into the src and 
+// writes it to the dst frame with desired translation.
+               if(!global_target_src)
+                       global_target_src = new VFrame(w, h, color_model);
+               if(!global_target_dst)
+                       global_target_dst = new VFrame(w, h, color_model);
+
+
+// Load the global frames
+               if(need_reload)
+               {
+                       read_frame(prev_global_ref, 
+                               reference_layer, 
+                               previous_frame_number, 
+                               frame_rate,
+                               0);
+               }
+
+               read_frame(current_global_ref, 
+                       reference_layer, 
+                       start_position, 
+                       frame_rate,
+                       0);
+               read_frame(global_target_src,
+                       target_layer,
+                       start_position,
+                       frame_rate,
+                       0);
+
+
+
+// Global followed by rotate
+               if(config.rotate)
+               {
+// Must translate the previous global reference by the current global
+// accumulation vector to match the current global reference.
+// The center of the search area is always the user value + the accumulation
+// vector.
+                       if(!prev_rotate_ref)
+                               prev_rotate_ref = new VFrame(w, h, color_model);
+// The current global reference is the current rotation reference.
+                       if(!current_rotate_ref)
+                               current_rotate_ref = new VFrame(w, h, color_model);
+                       current_rotate_ref->copy_from(current_global_ref);
+
+// The global target destination is copied to the rotation target source
+// then written to the rotation output with rotation.
+// The pivot for the rotation is the center of the search area 
+// if we're tracking.
+// The pivot is fixed to the user position if we're compensating.
+                       if(!rotate_target_src)
+                               rotate_target_src = new VFrame(w, h, color_model);
+                       if(!rotate_target_dst)
+                               rotate_target_dst = new VFrame(w,h , color_model);
+               }
+       }
+       else
+// Rotation only
+       if(config.rotate)
+       {
+// Rotation reads the previous reference frame and compares it with current 
+// reference frame.
+               if(!prev_rotate_ref)
+                       prev_rotate_ref = new VFrame(w, h, color_model);
+               if(!current_rotate_ref)
+                       current_rotate_ref = new VFrame(w, h, color_model);
+
+// Rotation loads target frame to temporary, rotates it, and writes it to the
+// target frame.  The pivot is always fixed.
+               if(!rotate_target_src)
+                       rotate_target_src = new VFrame(w, h, color_model);
+               if(!rotate_target_dst)
+                       rotate_target_dst = new VFrame(w,h , color_model);
+
+
+// Load the rotate frames
+               if(need_reload)
+               {
+                       read_frame(prev_rotate_ref, 
+                               reference_layer, 
+                               previous_frame_number, 
+                               frame_rate,
+                               0);
+               }
+               read_frame(current_rotate_ref, 
+                       reference_layer, 
+                       start_position, 
+                       frame_rate,
+                       0);
+               read_frame(rotate_target_src,
+                       target_layer,
+                       start_position,
+                       frame_rate,
+                       0);
+       }
+
+
+
+
+
+
+
+
+
+
+       if(!skip_current)
+       {
+// Get position change from previous frame to current frame
+               if(config.global) process_global();
+// Get rotation change from previous frame to current frame
+               if(config.rotate) process_rotation();
+//frame[target_layer]->copy_from(prev_rotate_ref);
+//frame[target_layer]->copy_from(current_rotate_ref);
+       }
+
+
+
+
+
+
+// Transfer the relevant target frame to the output
+       if(!skip_current)
+       {
+               if(config.rotate)
+               {
+                       frame[target_layer]->copy_from(rotate_target_dst);
+               }
+               else
+               {
+                       frame[target_layer]->copy_from(global_target_dst);
+               }
+       }
+       else
+// Read the target destination directly
+       {
+               read_frame(frame[target_layer],
+                       target_layer,
+                       start_position,
+                       frame_rate,
+                       0);
+       }
+
+       if(config.draw_vectors)
+       {
+               draw_vectors(frame[target_layer]);
+       }
+
+#ifdef DEBUG
+printf("MotionCVMain::process_buffer 100\n");
+#endif
+       return 0;
+}
+
+
+void MotionCVMain::clamp_scan(int w, 
+       int h, 
+       int *block_x1,
+       int *block_y1,
+       int *block_x2,
+       int *block_y2,
+       int *scan_x1,
+       int *scan_y1,
+       int *scan_x2,
+       int *scan_y2,
+       int use_absolute)
+{
+// printf("MotionCVMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w,
+// h,
+// *block_x1,
+// *block_y1,
+// *block_x2,
+// *block_y2,
+// *scan_x1,
+// *scan_y1,
+// *scan_x2,
+// *scan_y2,
+// use_absolute);
+
+       if(use_absolute)
+       {
+// scan is always out of range before block.
+               if(*scan_x1 < 0)
+               {
+                       int difference = -*scan_x1;
+                       *block_x1 += difference;
+                       *scan_x1 = 0;
+               }
+
+               if(*scan_y1 < 0)
+               {
+                       int difference = -*scan_y1;
+                       *block_y1 += difference;
+                       *scan_y1 = 0;
+               }
+
+               if(*scan_x2 > w)
+               {
+                       int difference = *scan_x2 - w;
+                       *block_x2 -= difference;
+                       *scan_x2 -= difference;
+               }
+
+               if(*scan_y2 > h)
+               {
+                       int difference = *scan_y2 - h;
+                       *block_y2 -= difference;
+                       *scan_y2 -= difference;
+               }
+
+               CLAMP(*scan_x1, 0, w);
+               CLAMP(*scan_y1, 0, h);
+               CLAMP(*scan_x2, 0, w);
+               CLAMP(*scan_y2, 0, h);
+       }
+       else
+       {
+               if(*scan_x1 < 0)
+               {
+                       int difference = -*scan_x1;
+                       *block_x1 += difference;
+                       *scan_x2 += difference;
+                       *scan_x1 = 0;
+               }
+
+               if(*scan_y1 < 0)
+               {
+                       int difference = -*scan_y1;
+                       *block_y1 += difference;
+                       *scan_y2 += difference;
+                       *scan_y1 = 0;
+               }
+
+               if(*scan_x2 - *block_x1 + *block_x2 > w)
+               {
+                       int difference = *scan_x2 - *block_x1 + *block_x2 - w;
+                       *block_x2 -= difference;
+               }
+
+               if(*scan_y2 - *block_y1 + *block_y2 > h)
+               {
+                       int difference = *scan_y2 - *block_y1 + *block_y2 - h;
+                       *block_y2 -= difference;
+               }
+
+//             CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
+//             CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
+//             CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
+//             CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
+       }
+
+// Sanity checks which break the calculation but should never happen if the
+// center of the block is inside the frame.
+       CLAMP(*block_x1, 0, w);
+       CLAMP(*block_x2, 0, w);
+       CLAMP(*block_y1, 0, h);
+       CLAMP(*block_y2, 0, h);
+
+// printf("MotionCVMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w,
+// h,
+// *block_x1,
+// *block_y1,
+// *block_x2,
+// *block_y2,
+// *scan_x1,
+// *scan_y1,
+// *scan_x2,
+// *scan_y2,
+// use_absolute);
+}
+
+
+
+void MotionCVMain::draw_vectors(VFrame *frame)
+{
+       int w = frame->get_w();
+       int h = frame->get_h();
+       int global_x1, global_y1;
+       int global_x2, global_y2;
+       int block_x, block_y;
+       int block_w, block_h;
+       int block_x1, block_y1;
+       int block_x2, block_y2;
+       int block_x3, block_y3;
+       int block_x4, block_y4;
+       int search_w, search_h;
+       int search_x1, search_y1;
+       int search_x2, search_y2;
+       //int search_x3, search_y3;
+       //int search_x4, search_y4;
+
+       if(config.global)
+       {
+// Get vector
+// Start of vector is center of previous block.
+// End of vector is total accumulation.
+               if(config.mode3 == MotionCVConfig::TRACK_SINGLE)
+               {
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
+                               100);
+                       global_y1 = (int64_t)(config.block_y *
+                               h / 
+                               100);
+                       global_x2 = global_x1 + total_dx / OVERSAMPLE;
+                       global_y2 = global_y1 + total_dy / OVERSAMPLE;
+//printf("MotionCVMain::draw_vectors %d %d %d %d %d %d\n", total_dx, total_dy, global_x1, global_y1, global_x2, global_y2);
+               }
+               else
+// Start of vector is center of previous block.
+// End of vector is current change.
+               if(config.mode3 == MotionCVConfig::PREVIOUS_SAME_BLOCK)
+               {
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
+                               100);
+                       global_y1 = (int64_t)(config.block_y *
+                               h / 
+                               100);
+                       global_x2 = global_x1 + current_dx / OVERSAMPLE;
+                       global_y2 = global_y1 + current_dy / OVERSAMPLE;
+               }
+               else
+               {
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
+                               100 + 
+                               (total_dx - current_dx) / 
+                               OVERSAMPLE);
+                       global_y1 = (int64_t)(config.block_y *
+                               h / 
+                               100 +
+                               (total_dy - current_dy) /
+                               OVERSAMPLE);
+                       global_x2 = (int64_t)(config.block_x * 
+                               w / 
+                               100 + 
+                               total_dx / 
+                               OVERSAMPLE);
+                       global_y2 = (int64_t)(config.block_y *
+                               h / 
+                               100 +
+                               total_dy /
+                               OVERSAMPLE);
+               }
+
+               block_x = global_x1;
+               block_y = global_y1;
+               block_w = config.global_block_w * w / 100;
+               block_h = config.global_block_h * h / 100;
+               block_x1 = block_x - block_w / 2;
+               block_y1 = block_y - block_h / 2;
+               block_x2 = block_x + block_w / 2;
+               block_y2 = block_y + block_h / 2;
+               search_w = config.global_range_w * w / 100;
+               search_h = config.global_range_h * h / 100;
+               search_x1 = block_x1 - search_w / 2;
+               search_y1 = block_y1 - search_h / 2;
+               search_x2 = block_x2 + search_w / 2;
+               search_y2 = block_y2 + search_h / 2;
+
+// printf("MotionCVMain::draw_vectors %d %d %d %d %d %d %d %d %d %d %d %d\n",
+// global_x1,
+// global_y1,
+// block_w,
+// block_h,
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// search_x1,
+// search_y1,
+// search_x2,
+// search_y2);
+
+               clamp_scan(w, 
+                       h, 
+                       &block_x1,
+                       &block_y1,
+                       &block_x2,
+                       &block_y2,
+                       &search_x1,
+                       &search_y1,
+                       &search_x2,
+                       &search_y2,
+                       1);
+
+// Vector
+               draw_arrow(frame, global_x1, global_y1, global_x2, global_y2);
+
+// Macroblock
+               draw_line(frame, block_x1, block_y1, block_x2, block_y1);
+               draw_line(frame, block_x2, block_y1, block_x2, block_y2);
+               draw_line(frame, block_x2, block_y2, block_x1, block_y2);
+               draw_line(frame, block_x1, block_y2, block_x1, block_y1);
+
+
+// Search area
+               draw_line(frame, search_x1, search_y1, search_x2, search_y1);
+               draw_line(frame, search_x2, search_y1, search_x2, search_y2);
+               draw_line(frame, search_x2, search_y2, search_x1, search_y2);
+               draw_line(frame, search_x1, search_y2, search_x1, search_y1);
+
+// Block should be endpoint of motion
+               if(config.rotate)
+               {
+                       block_x = global_x2;
+                       block_y = global_y2;
+               }
+       }
+       else
+       {
+               block_x = (int64_t)(config.block_x * w / 100);
+               block_y = (int64_t)(config.block_y * h / 100);
+       }
+
+       block_w = config.rotation_block_w * w / 100;
+       block_h = config.rotation_block_h * h / 100;
+       if(config.rotate)
+       {
+               float angle = total_angle * 2 * M_PI / 360;
+               double base_angle1 = atan((float)block_h / block_w);
+               double base_angle2 = atan((float)block_w / block_h);
+               double target_angle1 = base_angle1 + angle;
+               double target_angle2 = base_angle2 + angle;
+               double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
+               block_x1 = (int)(block_x - cos(target_angle1) * radius);
+               block_y1 = (int)(block_y - sin(target_angle1) * radius);
+               block_x2 = (int)(block_x + sin(target_angle2) * radius);
+               block_y2 = (int)(block_y - cos(target_angle2) * radius);
+               block_x3 = (int)(block_x - sin(target_angle2) * radius);
+               block_y3 = (int)(block_y + cos(target_angle2) * radius);
+               block_x4 = (int)(block_x + cos(target_angle1) * radius);
+               block_y4 = (int)(block_y + sin(target_angle1) * radius);
+
+               draw_line(frame, block_x1, block_y1, block_x2, block_y2);
+               draw_line(frame, block_x2, block_y2, block_x4, block_y4);
+               draw_line(frame, block_x4, block_y4, block_x3, block_y3);
+               draw_line(frame, block_x3, block_y3, block_x1, block_y1);
+
+
+// Center
+               if(!config.global)
+               {
+                       draw_line(frame, block_x, block_y - 5, block_x, block_y + 6);
+                       draw_line(frame, block_x - 5, block_y, block_x + 6, block_y);
+               }
+       }
+}
+
+
+
+void MotionCVMain::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 MotionCVMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
+{
+       int w = labs(x2 - x1);
+       int h = labs(y2 - y1);
+//printf("MotionCVMain::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("MotionCVMain::draw_line 2\n");
+}
+
+#define ARROW_SIZE 10
+void MotionCVMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
+{
+       double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
+       double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
+       double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
+       int x3;
+       int y3;
+       int x4;
+       int y4;
+       if(x2 < x1)
+       {
+               x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
+               y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
+               x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
+               y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
+       }
+       else
+       {
+               x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
+               y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
+               x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
+               y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
+       }
+
+// Main vector
+       draw_line(frame, x1, y1, x2, y2);
+//     draw_line(frame, x1, y1 + 1, x2, y2 + 1);
+
+// Arrow line
+       if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
+//     draw_line(frame, x2, y2 + 1, x3, y3 + 1);
+// Arrow line
+       if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
+//     draw_line(frame, x2, y2 + 1, x4, y4 + 1);
+}
+
+
+
+
+#define ABS_DIFF(type, temp_type, multiplier, components) \
+{ \
+       temp_type result_temp = 0; \
+       for(int i = 0; i < h; i++) \
+       { \
+               type *prev_row = (type*)prev_ptr; \
+               type *current_row = (type*)current_ptr; \
+               for(int j = 0; j < w; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               temp_type difference; \
+                               difference = *prev_row++ - *current_row++; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
+                       } \
+                       if(components == 4) \
+                       { \
+                               prev_row++; \
+                               current_row++; \
+                       } \
+               } \
+               prev_ptr += row_bytes; \
+               current_ptr += row_bytes; \
+       } \
+       result = (int64_t)(result_temp * multiplier); \
+}
+
+int64_t MotionCVMain::abs_diff(unsigned char *prev_ptr,
+       unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model)
+{
+       int64_t result = 0;
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       ABS_DIFF(float, double, 0x10000, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       ABS_DIFF(float, double, 0x10000, 4)
+                       break;
+               case BC_YUV888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_YUV161616:
+                       ABS_DIFF(uint16_t, int64_t, 1, 3)
+                       break;
+               case BC_YUVA16161616:
+                       ABS_DIFF(uint16_t, int64_t, 1, 4)
+                       break;
+       }
+       return result;
+}
+
+
+
+#define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
+{ \
+       temp_type result_temp = 0; \
+       temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
+       temp_type y1_fraction = 0x100 - y2_fraction; \
+       temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
+       temp_type x1_fraction = 0x100 - x2_fraction; \
+       for(int i = 0; i < h_sub; i++) \
+       { \
+               type *prev_row1 = (type*)prev_ptr; \
+               type *prev_row2 = (type*)prev_ptr + components; \
+               type *prev_row3 = (type*)(prev_ptr + row_bytes); \
+               type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
+               type *current_row = (type*)current_ptr; \
+               for(int j = 0; j < w_sub; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               temp_type difference; \
+                               temp_type prev_value = \
+                                       (*prev_row1++ * x1_fraction * y1_fraction + \
+                                       *prev_row2++ * x2_fraction * y1_fraction + \
+                                       *prev_row3++ * x1_fraction * y2_fraction + \
+                                       *prev_row4++ * x2_fraction * y2_fraction) / \
+                                       0x100 / 0x100; \
+                               temp_type current_value = *current_row++; \
+                               difference = prev_value - current_value; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
+                       } \
+ \
+                       if(components == 4) \
+                       { \
+                               prev_row1++; \
+                               prev_row2++; \
+                               prev_row3++; \
+                               prev_row4++; \
+                               current_row++; \
+                       } \
+               } \
+               prev_ptr += row_bytes; \
+               current_ptr += row_bytes; \
+       } \
+       result = (int64_t)(result_temp * multiplier); \
+}
+
+
+
+
+int64_t MotionCVMain::abs_diff_sub(unsigned char *prev_ptr,
+       unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model,
+       int sub_x,
+       int sub_y)
+{
+       int h_sub = h - 1;
+       int w_sub = w - 1;
+       int64_t result = 0;
+
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       ABS_DIFF_SUB(float, double, 0x10000, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       ABS_DIFF_SUB(float, double, 0x10000, 4)
+                       break;
+               case BC_YUV888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_YUV161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
+                       break;
+               case BC_YUVA16161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
+                       break;
+       }
+       return result;
+}
+
+
+
+
+
+MotionCVScanPackage::MotionCVScanPackage()
+ : LoadPackage()
+{
+       valid = 1;
+}
+
+
+
+
+
+
+MotionCVScanUnit::MotionCVScanUnit(MotionCVScan *server, 
+       MotionCVMain *plugin)
+ : LoadClient(server)
+{
+       this->plugin = plugin;
+       this->server = server;
+       cache_lock = new Mutex("MotionCVScanUnit::cache_lock");
+}
+
+MotionCVScanUnit::~MotionCVScanUnit()
+{
+       delete cache_lock;
+}
+
+
+
+void MotionCVScanUnit::process_package(LoadPackage *package)
+{
+       MotionCVScanPackage *pkg = (MotionCVScanPackage*)package;
+       //int w = server->current_frame->get_w();
+       //int h = server->current_frame->get_h();
+       int color_model = server->current_frame->get_color_model();
+       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+       int row_bytes = server->current_frame->get_bytes_per_line();
+
+
+
+
+
+
+
+
+
+
+
+
+// Single pixel
+       if(!server->subpixel)
+       {
+               int search_x = pkg->scan_x1 + (pkg->pixel % (pkg->scan_x2 - pkg->scan_x1));
+               int search_y = pkg->scan_y1 + (pkg->pixel / (pkg->scan_x2 - pkg->scan_x1));
+
+// Try cache
+               pkg->difference1 = server->get_cache(search_x, search_y);
+               if(pkg->difference1 < 0)
+               {
+//printf("MotionCVScanUnit::process_package 1 %d %d\n", 
+//search_x, search_y, pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1);
+// Pointers to first pixel in each block
+                       unsigned char *prev_ptr = server->previous_frame->get_rows()[
+                               search_y] +     
+                               search_x * pixel_size;
+                       unsigned char *current_ptr = server->current_frame->get_rows()[
+                               pkg->block_y1] +
+                               pkg->block_x1 * pixel_size;
+// Scan block
+                       pkg->difference1 = plugin->abs_diff(prev_ptr,
+                               current_ptr,
+                               row_bytes,
+                               pkg->block_x2 - pkg->block_x1,
+                               pkg->block_y2 - pkg->block_y1,
+                               color_model);
+//printf("MotionCVScanUnit::process_package 2\n");
+                       server->put_cache(search_x, search_y, pkg->difference1);
+               }
+       }
+
+
+
+
+
+
+
+       else
+
+
+
+
+
+
+
+
+// Sub pixel
+       {
+               int sub_x = pkg->pixel % (OVERSAMPLE * 2 - 1) + 1;
+               int sub_y = pkg->pixel / (OVERSAMPLE * 2 - 1) + 1;
+
+               if(plugin->config.horizontal_only)
+               {
+                       sub_y = 0;
+               }
+
+               if(plugin->config.vertical_only)
+               {
+                       sub_x = 0;
+               }
+
+               int search_x = pkg->scan_x1 + sub_x / OVERSAMPLE;
+               int search_y = pkg->scan_y1 + sub_y / OVERSAMPLE;
+               sub_x %= OVERSAMPLE;
+               sub_y %= OVERSAMPLE;
+
+
+               unsigned char *prev_ptr = server->previous_frame->get_rows()[
+                       search_y] +
+                       search_x * pixel_size;
+               unsigned char *current_ptr = server->current_frame->get_rows()[
+                       pkg->block_y1] +
+                       pkg->block_x1 * pixel_size;
+
+// With subpixel, there are two ways to compare each position, one by shifting
+// the previous frame and two by shifting the current frame.
+               pkg->difference1 = plugin->abs_diff_sub(prev_ptr,
+                       current_ptr,
+                       row_bytes,
+                       pkg->block_x2 - pkg->block_x1,
+                       pkg->block_y2 - pkg->block_y1,
+                       color_model,
+                       sub_x,
+                       sub_y);
+               pkg->difference2 = plugin->abs_diff_sub(current_ptr,
+                       prev_ptr,
+                       row_bytes,
+                       pkg->block_x2 - pkg->block_x1,
+                       pkg->block_y2 - pkg->block_y1,
+                       color_model,
+                       sub_x,
+                       sub_y);
+// printf("MotionCVScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
+// sub_x,
+// sub_y,
+// search_x,
+// search_y,
+// pkg->difference1,
+// pkg->difference2);
+       }
+
+
+
+
+}
+
+
+
+
+
+
+
+
+
+
+int64_t MotionCVScanUnit::get_cache(int x, int y)
+{
+       int64_t result = -1;
+       cache_lock->lock("MotionCVScanUnit::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               MotionCVScanCache *ptr = cache.values[i];
+               if(ptr->x == x && ptr->y == y)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void MotionCVScanUnit::put_cache(int x, int y, int64_t difference)
+{
+       MotionCVScanCache *ptr = new MotionCVScanCache(x, y, difference);
+       cache_lock->lock("MotionCVScanUnit::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+
+
+
+
+
+
+MotionCVScan::MotionCVScan(MotionCVMain *plugin, 
+       int total_clients,
+       int total_packages)
+ : LoadServer(
+//1, 1 
+total_clients, total_packages 
+)
+{
+       this->plugin = plugin;
+       cache_lock = new Mutex("MotionCVScan::cache_lock");
+}
+
+MotionCVScan::~MotionCVScan()
+{
+       delete cache_lock;
+}
+
+
+void MotionCVScan::init_packages()
+{
+// Set package coords
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               MotionCVScanPackage *pkg = (MotionCVScanPackage*)get_package(i);
+
+               pkg->block_x1 = block_x1;
+               pkg->block_x2 = block_x2;
+               pkg->block_y1 = block_y1;
+               pkg->block_y2 = block_y2;
+               pkg->scan_x1 = scan_x1;
+               pkg->scan_x2 = scan_x2;
+               pkg->scan_y1 = scan_y1;
+               pkg->scan_y2 = scan_y2;
+               pkg->pixel = (int64_t)i * (int64_t)total_pixels / (int64_t)total_steps;
+               pkg->difference1 = 0;
+               pkg->difference2 = 0;
+               pkg->dx = 0;
+               pkg->dy = 0;
+               pkg->valid = 1;
+       }
+}
+
+LoadClient* MotionCVScan::new_client()
+{
+       return new MotionCVScanUnit(this, plugin);
+}
+
+LoadPackage* MotionCVScan::new_package()
+{
+       return new MotionCVScanPackage;
+}
+
+
+void MotionCVScan::scan_frame(VFrame *previous_frame,
+       VFrame *current_frame)
+{
+       this->previous_frame = previous_frame;
+       this->current_frame = current_frame;
+       subpixel = 0;
+
+       cache.remove_all_objects();
+
+
+// Single macroblock
+       int w = current_frame->get_w();
+       int h = current_frame->get_h();
+
+// Initial search parameters
+       int scan_w = w * plugin->config.global_range_w / 100;
+       int scan_h = h * plugin->config.global_range_h / 100;
+       int block_w = w * plugin->config.global_block_w / 100;
+       int block_h = h * plugin->config.global_block_h / 100;
+
+// Location of block in previous frame
+       block_x1 = (int)(w * plugin->config.block_x / 100 - block_w / 2);
+       block_y1 = (int)(h * plugin->config.block_y / 100 - block_h / 2);
+       block_x2 = (int)(w * plugin->config.block_x / 100 + block_w / 2);
+       block_y2 = (int)(h * plugin->config.block_y / 100 + block_h / 2);
+
+// Offset to location of previous block.  This offset needn't be very accurate
+// since it's the offset of the previous image and current image we want.
+       if(plugin->config.mode3 == MotionCVConfig::TRACK_PREVIOUS)
+       {
+               block_x1 += plugin->total_dx / OVERSAMPLE;
+               block_y1 += plugin->total_dy / OVERSAMPLE;
+               block_x2 += plugin->total_dx / OVERSAMPLE;
+               block_y2 += plugin->total_dy / OVERSAMPLE;
+       }
+
+       skip = 0;
+
+       switch(plugin->config.mode2)
+       {
+// Don't calculate
+               case MotionCVConfig::NO_CALCULATE:
+                       dx_result = 0;
+                       dy_result = 0;
+                       skip = 1;
+                       break;
+
+               case MotionCVConfig::LOAD:
+               {
+// Load result from disk
+                       char string[BCTEXTLEN];
+                       sprintf(string, "%s%06jd", MOTION_FILE, plugin->get_source_position());
+                       FILE *input = fopen(string, "r");
+                       if(input)
+                       {
+                               fscanf(input, 
+                                       "%d %d", 
+                                       &dx_result,
+                                       &dy_result);
+                               fclose(input);
+                               skip = 1;
+                       }
+                       break;
+               }
+
+// Scan from scratch
+               default:
+                       skip = 0;
+                       break;
+       }
+
+// Perform scan
+       if(!skip)
+       {
+// Location of block in current frame
+               int x_result = block_x1;
+               int y_result = block_y1;
+
+// printf("MotionCVScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
+// block_x1 + block_w / 2,
+// block_y1 + block_h / 2,
+// block_w,
+// block_h,
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2);
+
+               while(1)
+               {
+                       scan_x1 = x_result - scan_w / 2;
+                       scan_y1 = y_result - scan_h / 2;
+                       scan_x2 = x_result + scan_w / 2;
+                       scan_y2 = y_result + scan_h / 2;
+
+
+
+// Zero out requested values
+                       if(plugin->config.horizontal_only)
+                       {
+                               scan_y1 = block_y1;
+                               scan_y2 = block_y1 + 1;
+                       }
+                       if(plugin->config.vertical_only)
+                       {
+                               scan_x1 = block_x1;
+                               scan_x2 = block_x1 + 1;
+                       }
+
+// printf("MotionCVScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// scan_x1,
+// scan_y1,
+// scan_x2,
+// scan_y2);
+// Clamp the block coords before the scan so we get useful scan coords.
+                       MotionCVMain::clamp_scan(w, 
+                               h, 
+                               &block_x1,
+                               &block_y1,
+                               &block_x2,
+                               &block_y2,
+                               &scan_x1,
+                               &scan_y1,
+                               &scan_x2,
+                               &scan_y2,
+                               0);
+// printf("MotionCVScan::scan_frame 1\n    block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n    scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n    x_result=%d y_result=%d\n", 
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// scan_x1, 
+// scan_y1, 
+// scan_x2, 
+// scan_y2, 
+// x_result, 
+// y_result);
+
+
+// Give up if invalid coords.
+                       if(scan_y2 <= scan_y1 ||
+                               scan_x2 <= scan_x1 ||
+                               block_x2 <= block_x1 ||
+                               block_y2 <= block_y1)
+                               break;
+
+// For subpixel, the top row and left column are skipped
+                       if(subpixel)
+                       {
+                               if(plugin->config.horizontal_only ||
+                                       plugin->config.vertical_only)
+                               {
+                                       total_pixels = 4 * OVERSAMPLE * OVERSAMPLE - 4 * OVERSAMPLE;
+                               }
+                               else
+                               {
+                                       total_pixels = 4 * OVERSAMPLE;
+                               }
+
+                               total_steps = total_pixels;
+
+                               set_package_count(total_steps);
+                               process_packages();
+
+// Get least difference
+                               int64_t min_difference = -1;
+                               for(int i = 0; i < get_total_packages(); i++)
+                               {
+                                       MotionCVScanPackage *pkg = (MotionCVScanPackage*)get_package(i);
+                                       if(pkg->difference1 < min_difference || min_difference == -1)
+                                       {
+                                               min_difference = pkg->difference1;
+
+                                               if(plugin->config.vertical_only)
+                                                       x_result = scan_x1 * OVERSAMPLE;
+                                               else
+                                                       x_result = scan_x1 * OVERSAMPLE + 
+                                                               (pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1;
+                                               
+                                               if(plugin->config.horizontal_only)
+                                                       y_result = scan_y1 * OVERSAMPLE;
+                                               else
+                                                       y_result = scan_y1 * OVERSAMPLE + 
+                                                               (pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1;
+
+
+// Fill in results
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+                                       }
+
+                                       if(pkg->difference2 < min_difference)
+                                       {
+                                               min_difference = pkg->difference2;
+
+                                               if(plugin->config.vertical_only)
+                                                       x_result = scan_x1 * OVERSAMPLE;
+                                               else
+                                                       x_result = scan_x2 * OVERSAMPLE -
+                                                               ((pkg->pixel % (OVERSAMPLE * 2 - 1)) + 1);
+
+                                               if(plugin->config.horizontal_only)
+                                                       y_result = scan_y1 * OVERSAMPLE;
+                                               else
+                                                       y_result = scan_y2 * OVERSAMPLE -
+                                                               ((pkg->pixel / (OVERSAMPLE * 2 - 1)) + 1);
+
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+                                       }
+                               }
+
+//printf("MotionCVScan::scan_frame 1 %d %d %d %d\n", block_x1, block_y1, x_result, y_result);
+                               break;
+                       }
+                       else
+                       {
+                               total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
+                               total_steps = MIN(plugin->config.global_positions, total_pixels);
+
+                               set_package_count(total_steps);
+                               process_packages();
+
+// Get least difference
+                               int64_t min_difference = -1;
+                               for(int i = 0; i < get_total_packages(); i++)
+                               {
+                                       MotionCVScanPackage *pkg = (MotionCVScanPackage*)get_package(i);
+                                       if(pkg->difference1 < min_difference || min_difference == -1)
+                                       {
+                                               min_difference = pkg->difference1;
+                                               x_result = scan_x1 + (pkg->pixel % (scan_x2 - scan_x1));
+                                               y_result = scan_y1 + (pkg->pixel / (scan_x2 - scan_x1));
+                                               x_result *= OVERSAMPLE;
+                                               y_result *= OVERSAMPLE;
+                                       }
+                               }
+
+// printf("MotionCVScan::scan_frame 10 total_steps=%d total_pixels=%d subpixel=%d\n",
+// total_steps, 
+// total_pixels,
+// subpixel);
+// 
+// printf("    scan w=%d h=%d scan x1=%d y1=%d x2=%d y2=%d\n",
+// scan_w,
+// scan_h, 
+// scan_x1,
+// scan_y1,
+// scan_x2,
+// scan_y2);
+// 
+// printf("MotionCVScan::scan_frame 2 block x1=%d y1=%d x2=%d y2=%d result x=%.2f y=%.2f\n", 
+// block_x1, 
+// block_y1, 
+// block_x2,
+// block_y2,
+// (float)x_result / 4, 
+// (float)y_result / 4);
+
+
+// If a new search is required, rescale results back to pixels.
+                               if(total_steps >= total_pixels)
+                               {
+// Single pixel accuracy reached.  Now do exhaustive subpixel search.
+                                       if(plugin->config.mode1 == MotionCVConfig::STABILIZE ||
+                                               plugin->config.mode1 == MotionCVConfig::TRACK ||
+                                               plugin->config.mode1 == MotionCVConfig::NOTHING)
+                                       {
+                                               x_result /= OVERSAMPLE;
+                                               y_result /= OVERSAMPLE;
+                                               scan_w = 2;
+                                               scan_h = 2;
+                                               subpixel = 1;
+                                       }
+                                       else
+                                       {
+// Fill in results and quit
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+                                               break;
+                                       }
+                               }
+                               else
+// Reduce scan area and try again
+                               {
+                                       scan_w = (scan_x2 - scan_x1) / 2;
+                                       scan_h = (scan_y2 - scan_y1) / 2;
+                                       x_result /= OVERSAMPLE;
+                                       y_result /= OVERSAMPLE;
+                               }
+                       }
+               }
+
+               dx_result *= -1;
+               dy_result *= -1;
+
+               // Add offsets from the "tracked single frame"
+               if (plugin->config.addtrackedframeoffset) {
+                 int tf_dx_result, tf_dy_result;
+                 char string[BCTEXTLEN];
+                 sprintf(string, "%s%06jd", MOTION_FILE, plugin->config.track_frame);
+                 FILE *input = fopen(string, "r");
+                 if(input)
+                   {
+                     fscanf(input, 
+                            "%d %d", 
+                            &tf_dx_result,
+                            &tf_dy_result);
+                     dx_result += tf_dx_result;
+                     dy_result += tf_dy_result;
+                     fclose(input);
+                   }
+               }
+
+       }
+
+
+
+
+
+
+// Write results
+       if(plugin->config.mode2 == MotionCVConfig::SAVE)
+       {
+               char string[BCTEXTLEN];
+               sprintf(string, 
+                       "%s%06jd", 
+                       MOTION_FILE, 
+                       plugin->get_source_position());
+               FILE *output = fopen(string, "w");
+               if(output)
+               {
+                       fprintf(output, 
+                               "%d %d\n",
+                               dx_result,
+                               dy_result);
+                       fclose(output);
+               }
+               else
+               {
+                       perror("MotionCVScan::scan_frame SAVE 1");
+               }
+       }
+
+#ifdef DEBUG
+printf("MotionCVScan::scan_frame 10 dx=%.2f dy=%.2f\n", 
+(float)this->dx_result / OVERSAMPLE,
+(float)this->dy_result / OVERSAMPLE);
+#endif
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int64_t MotionCVScan::get_cache(int x, int y)
+{
+       int64_t result = -1;
+       cache_lock->lock("MotionCVScan::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               MotionCVScanCache *ptr = cache.values[i];
+               if(ptr->x == x && ptr->y == y)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void MotionCVScan::put_cache(int x, int y, int64_t difference)
+{
+       MotionCVScanCache *ptr = new MotionCVScanCache(x, y, difference);
+       cache_lock->lock("MotionCVScan::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+MotionCVScanCache::MotionCVScanCache(int x, int y, int64_t difference)
+{
+       this->x = x;
+       this->y = y;
+       this->difference = difference;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+RotateCVScanPackage::RotateCVScanPackage()
+{
+}
+
+
+RotateCVScanUnit::RotateCVScanUnit(RotateCVScan *server, MotionCVMain *plugin)
+ : LoadClient(server)
+{
+       this->server = server;
+       this->plugin = plugin;
+       rotater = 0;
+       temp = 0;
+}
+
+RotateCVScanUnit::~RotateCVScanUnit()
+{
+       delete rotater;
+       delete temp;
+}
+
+void RotateCVScanUnit::process_package(LoadPackage *package)
+{
+       if(server->skip) return;
+       RotateCVScanPackage *pkg = (RotateCVScanPackage*)package;
+
+       if((pkg->difference = server->get_cache(pkg->angle)) < 0)
+       {
+//printf("RotateCVScanUnit::process_package 1\n");
+               int color_model = server->previous_frame->get_color_model();
+               int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+               int row_bytes = server->previous_frame->get_bytes_per_line();
+
+               if(!rotater)
+                       rotater = new AffineEngine(1, 1);
+               if(!temp) temp = new VFrame(
+                       server->previous_frame->get_w(),
+                       server->previous_frame->get_h(),
+                       color_model);
+
+
+// RotateCV original block size
+               rotater->set_viewport(server->block_x1, 
+                       server->block_y1,
+                       server->block_x2 - server->block_x1,
+                       server->block_y2 - server->block_y1);
+               rotater->set_pivot(server->block_x, server->block_y);
+//pkg->angle = 2;
+               rotater->rotate(temp,
+                       server->previous_frame,
+                       pkg->angle);
+// Clamp coordinates
+               int x1 = server->scan_x;
+               int y1 = server->scan_y;
+               int x2 = x1 + server->scan_w;
+               int y2 = y1 + server->scan_h;
+               x2 = MIN(temp->get_w(), x2);
+               y2 = MIN(temp->get_h(), y2);
+               x2 = MIN(server->current_frame->get_w(), x2);
+               y2 = MIN(server->current_frame->get_h(), y2);
+               x1 = MAX(0, x1);
+               y1 = MAX(0, y1);
+
+               if(x2 > x1 && y2 > y1)
+               {
+                       pkg->difference = plugin->abs_diff(
+                               temp->get_rows()[y1] + x1 * pixel_size,
+                               server->current_frame->get_rows()[y1] + x1 * pixel_size,
+                               row_bytes,
+                               x2 - x1,
+                               y2 - y1,
+                               color_model);
+//printf("RotateCVScanUnit::process_package %d\n", __LINE__);
+                       server->put_cache(pkg->angle, pkg->difference);
+                }
+
+// printf("RotateCVScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%lld\n", 
+// server->block_x1, 
+// server->block_y1,
+// server->block_x2 - server->block_x1,
+// server->block_y2 - server->block_y1,
+// server->block_x,
+// server->block_y,
+// pkg->angle, 
+// server->scan_w,
+// server->scan_h,
+// pkg->difference);
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+RotateCVScan::RotateCVScan(MotionCVMain *plugin, 
+       int total_clients, 
+       int total_packages)
+ : LoadServer(
+//1, 1 
+total_clients, total_packages 
+)
+{
+       this->plugin = plugin;
+       cache_lock = new Mutex("RotateCVScan::cache_lock");
+}
+
+
+RotateCVScan::~RotateCVScan()
+{
+       delete cache_lock;
+}
+
+void RotateCVScan::init_packages()
+{
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               RotateCVScanPackage *pkg = (RotateCVScanPackage*)get_package(i);
+               pkg->angle = i * 
+                       (scan_angle2 - scan_angle1) / 
+                       (total_steps - 1) + 
+                       scan_angle1;
+       }
+}
+
+LoadClient* RotateCVScan::new_client()
+{
+       return new RotateCVScanUnit(this, plugin);
+}
+
+LoadPackage* RotateCVScan::new_package()
+{
+       return new RotateCVScanPackage;
+}
+
+
+float RotateCVScan::scan_frame(VFrame *previous_frame,
+       VFrame *current_frame,
+       int block_x,
+       int block_y)
+{
+       skip = 0;
+       this->block_x = block_x;
+       this->block_y = block_y;
+
+       switch(plugin->config.mode2)
+       {
+               case MotionCVConfig::NO_CALCULATE:
+                       result = 0;
+                       skip = 1;
+                       break;
+
+               case MotionCVConfig::LOAD:
+               {
+                       char string[BCTEXTLEN];
+                       sprintf(string, "%s%06jd", ROTATION_FILE, plugin->get_source_position());
+                       FILE *input = fopen(string, "r");
+                       if(input)
+                       {
+                               fscanf(input, "%f", &result);
+                               fclose(input);
+                               skip = 1;
+                       }
+                       else
+                       {
+                               perror("RotateCVScan::scan_frame LOAD");
+                       }
+                       break;
+               }
+       }
+
+
+
+
+
+
+
+
+       this->previous_frame = previous_frame;
+       this->current_frame = current_frame;
+       int w = current_frame->get_w();
+       int h = current_frame->get_h();
+       int block_w = w * plugin->config.rotation_block_w / 100;
+       int block_h = h * plugin->config.rotation_block_h / 100;
+
+       if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
+       if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
+       if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
+       if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
+
+       block_x1 = this->block_x - block_w / 2;
+       block_x2 = this->block_x + block_w / 2;
+       block_y1 = this->block_y - block_h / 2;
+       block_y2 = this->block_y + block_h / 2;
+
+
+// Calculate the maximum area available to scan after rotation.
+// Must be calculated from the starting range because of cache.
+// Get coords of rectangle after rotation.
+       double center_x = this->block_x;
+       double center_y = this->block_y;
+       double max_angle = plugin->config.rotation_range;
+       double base_angle1 = atan((float)block_h / block_w);
+       double base_angle2 = atan((float)block_w / block_h);
+       double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
+       double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
+       double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
+       double x1 = center_x - cos(target_angle1) * radius;
+       double y1 = center_y - sin(target_angle1) * radius;
+       double x2 = center_x + sin(target_angle2) * radius;
+       double y2 = center_y - cos(target_angle2) * radius;
+       double x3 = center_x - sin(target_angle2) * radius;
+       double y3 = center_y + cos(target_angle2) * radius;
+
+// Track top edge to find greatest area.
+       double max_area1 = 0;
+       //double max_x1 = 0;
+       double max_y1 = 0;
+       for(double x = x1; x < x2; x++)
+       {
+               double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+               if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area1)
+                       {
+                               max_area1 = area;
+                               //max_x1 = x;
+                               max_y1 = y;
+                       }
+               }
+       }
+
+// Track left edge to find greatest area.
+       double max_area2 = 0;
+       double max_x2 = 0;
+       //double max_y2 = 0;
+       for(double y = y1; y < y3; y++)
+       {
+               double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
+               if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area2)
+                       {
+                               max_area2 = area;
+                               max_x2 = x;
+                               //max_y2 = y;
+                       }
+               }
+       }
+
+       double max_x, max_y;
+       max_x = max_x2;
+       max_y = max_y1;
+
+// Get reduced scan coords
+       scan_w = (int)(fabs(max_x - center_x) * 2);
+       scan_h = (int)(fabs(max_y - center_y) * 2);
+       scan_x = (int)(center_x - scan_w / 2);
+       scan_y = (int)(center_y - scan_h / 2);
+// printf("RotateCVScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n", 
+// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
+// printf("    angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
+
+// Determine min angle from size of block
+       double angle1 = atan((double)block_h / block_w);
+       double angle2 = atan((double)(block_h - 1) / (block_w + 1));
+       double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
+       min_angle = MAX(min_angle, MIN_ANGLE);
+
+#ifdef DEBUG
+printf("RotateCVScan::scan_frame min_angle=%f\n", min_angle * 360 / 2 / M_PI);
+#endif
+
+       cache.remove_all_objects();
+       if(!skip)
+       {
+// Initial search range
+               float angle_range = (float)plugin->config.rotation_range;
+               result = 0;
+               total_steps = plugin->config.rotate_positions;
+
+
+               while(angle_range >= min_angle * total_steps)
+               {
+                       scan_angle1 = result - angle_range;
+                       scan_angle2 = result + angle_range;
+
+
+                       set_package_count(total_steps);
+//set_package_count(1);
+                       process_packages();
+
+                       int64_t min_difference = -1;
+                       for(int i = 0; i < get_total_packages(); i++)
+                       {
+                               RotateCVScanPackage *pkg = (RotateCVScanPackage*)get_package(i);
+                               if(pkg->difference < min_difference || min_difference == -1)
+                               {
+                                       min_difference = pkg->difference;
+                                       result = pkg->angle;
+                               }
+//break;
+                       }
+
+                       angle_range /= 2;
+
+//break;
+               }
+       }
+
+
+       if(!skip && plugin->config.mode2 == MotionCVConfig::SAVE)
+       {
+               char string[BCTEXTLEN];
+               sprintf(string, 
+                       "%s%06jd", 
+                       ROTATION_FILE, 
+                       plugin->get_source_position());
+               FILE *output = fopen(string, "w");
+               if(output)
+               {
+                       fprintf(output, "%f\n", result);
+                       fclose(output);
+               }
+               else
+               {
+                       perror("RotateCVScan::scan_frame SAVE");
+               }
+       }
+
+#ifdef DEBUG
+printf("RotateCVScan::scan_frame 10 angle=%f\n", result);
+#endif
+       
+
+
+       return result;
+}
+
+int64_t RotateCVScan::get_cache(float angle)
+{
+       int64_t result = -1;
+       cache_lock->lock("RotateCVScan::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               RotateCVScanCache *ptr = cache.values[i];
+               if(fabs(ptr->angle - angle) <= MIN_ANGLE)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void RotateCVScan::put_cache(float angle, int64_t difference)
+{
+       RotateCVScanCache *ptr = new RotateCVScanCache(angle, difference);
+       cache_lock->lock("RotateCVScan::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+
+
+
+
+RotateCVScanCache::RotateCVScanCache(float angle, int64_t difference)
+{
+       this->angle = angle;
+       this->difference = difference;
+}
+
+
+
diff --git a/cinelerra-5.1/plugins/motion-cv/motion-cv.h b/cinelerra-5.1/plugins/motion-cv/motion-cv.h
new file mode 100644 (file)
index 0000000..c8788a0
--- /dev/null
@@ -0,0 +1,494 @@
+
+/*
+ * 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 MOTION_H
+#define MOTION_H
+
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "affine.inc"
+#include "bchash.inc"
+#include "filexml.inc"
+#include "keyframe.inc"
+#include "loadbalance.h"
+#include "overlayframe.inc"
+#include "pluginvclient.h"
+#include "rotateframe.inc"
+#include "vframe.inc"
+
+class MotionCVMain;
+class MotionCVWindow;
+class MotionCVScan;
+class RotateCVScan;
+
+
+#define OVERSAMPLE 4
+
+
+// Limits of global range in percent
+#define MIN_RADIUS 1
+#define MAX_RADIUS 50
+
+// Limits of rotation range in degrees
+#define MIN_ROTATION 1
+#define MAX_ROTATION 25
+
+// Limits of block size in percent.
+#define MIN_BLOCK 1
+#define MAX_BLOCK 100
+
+// Limits of block count
+#define MIN_BLOCKS 1
+#define MAX_BLOCKS 200
+
+// Precision of rotation
+#define MIN_ANGLE 0.0001
+
+#define TRACKING_FILE "/tmp/motion"
+
+class MotionCVConfig
+{
+public:
+       MotionCVConfig();
+
+       int equivalent(MotionCVConfig &that);
+       void copy_from(MotionCVConfig &that);
+       void interpolate(MotionCVConfig &prev, MotionCVConfig &next, 
+               int64_t prev_frame, int64_t next_frame, int64_t current_frame);
+       void boundaries();
+
+       int block_count;
+       int global_range_w;
+       int global_range_h;
+       int rotation_range;
+       int magnitude;
+       int return_speed;
+       int draw_vectors;
+// Percent of image size
+       int global_block_w;
+       int global_block_h;
+       int rotation_block_w;
+       int rotation_block_h;
+// Number of search positions in each refinement of the log search
+       int global_positions;
+       int rotate_positions;
+// Block position in percentage 0 - 100
+       double block_x;
+       double block_y;
+
+       int horizontal_only;
+       int vertical_only;
+       int global;
+       int rotate;
+       int addtrackedframeoffset;
+       char tracking_file[BCTEXTLEN];
+// Track or stabilize, single pixel, scan only, or nothing
+       int mode1;
+// Recalculate, no calculate, save, or load coordinates from disk
+       int mode2;
+// Track a single frame, previous frame, or previous frame same block
+       int mode3;
+       enum
+       {
+// mode1
+               TRACK,
+               STABILIZE,
+               TRACK_PIXEL,
+               STABILIZE_PIXEL,
+               NOTHING,
+// mode2
+               RECALCULATE,
+               SAVE,
+               LOAD,
+               NO_CALCULATE,
+// mode3
+               TRACK_SINGLE,
+               TRACK_PREVIOUS,
+               PREVIOUS_SAME_BLOCK
+       };
+// Number of single frame to track relative to timeline start
+       int64_t track_frame;
+// Master layer
+       int bottom_is_master;
+};
+
+
+
+
+class MotionCVMain : public PluginVClient
+{
+public:
+       MotionCVMain(PluginServer *server);
+       ~MotionCVMain();
+
+       int process_buffer(VFrame **frame,
+               int64_t start_position,
+               double frame_rate);
+       void process_global();
+       void process_rotation();
+       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_MEMBERS2(MotionCVConfig)
+
+
+       int64_t abs_diff(unsigned char *prev_ptr,
+               unsigned char *current_ptr,
+               int row_bytes,
+               int w,
+               int h,
+               int color_model);
+       int64_t abs_diff_sub(unsigned char *prev_ptr,
+               unsigned char *current_ptr,
+               int row_bytes,
+               int w,
+               int h,
+               int color_model,
+               int sub_x,
+               int sub_y);
+
+       static void clamp_scan(int w, 
+               int h, 
+               int *block_x1,
+               int *block_y1,
+               int *block_x2,
+               int *block_y2,
+               int *scan_x1,
+               int *scan_y1,
+               int *scan_x2,
+               int *scan_y2,
+               int use_absolute);
+       static void draw_pixel(VFrame *frame, int x, int y);
+       static void draw_line(VFrame *frame, int x1, int y1, int x2, int y2);
+       void draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2);
+
+// Number of the previous reference frame on the timeline.
+       int64_t previous_frame_number;
+// The frame compared with the previous frame to get the motion.
+// It is moved to compensate for motion and copied to the previous_frame.
+       VFrame *temp_frame;
+       MotionCVScan *engine;
+       RotateCVScan *motion_rotate;
+       OverlayFrame *overlayer;
+       AffineEngine *rotate_engine;
+
+// Accumulation of all global tracks since the plugin start.
+// Multiplied by OVERSAMPLE.
+       int total_dx;
+       int total_dy;
+
+// Rotation motion tracking
+       float total_angle;
+
+// Current motion vector for drawing vectors
+       int current_dx;
+       int current_dy;
+       float current_angle;
+
+       FILE *active_fp;
+       char active_file[BCTEXTLEN];
+       int get_line_key(const char *filename, int64_t key, char *line, int len);
+// add constant frame offset values
+       int dx_offset, dy_offset;
+       int64_t tracking_frame;
+// save/load result values
+       int save_dx, load_dx;
+       int save_dy, load_dy;
+       float save_dt, load_dt;
+
+// Oversampled current frame for motion estimation
+       int32_t *search_area;
+       int search_size;
+
+
+// The layer to track motion in.
+       int reference_layer;
+// The layer to apply motion in.
+       int target_layer;
+
+// Pointer to the source and destination of each operation.
+// These are fully allocated buffers.
+
+// The previous reference frame for global motion tracking
+       VFrame *prev_global_ref;
+// The current reference frame for global motion tracking
+       VFrame *current_global_ref;
+// The input target frame for global motion tracking
+       VFrame *global_target_src;
+// The output target frame for global motion tracking
+       VFrame *global_target_dst;
+
+// The previous reference frame for rotation tracking
+       VFrame *prev_rotate_ref;
+// The current reference frame for rotation tracking
+       VFrame *current_rotate_ref;
+// The input target frame for rotation tracking.
+       VFrame *rotate_target_src;
+// The output target frame for rotation tracking.
+       VFrame *rotate_target_dst;
+
+// The output of process_buffer
+       VFrame *output_frame;
+       int w;
+       int h;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class MotionCVScanPackage : public LoadPackage
+{
+public:
+       MotionCVScanPackage();
+
+// For multiple blocks
+       int block_x1, block_y1, block_x2, block_y2;
+       int scan_x1, scan_y1, scan_x2, scan_y2;
+       int dx;
+       int dy;
+       int64_t max_difference;
+       int64_t min_difference;
+       int64_t min_pixel;
+       int is_border;
+       int valid;
+// For single block
+       int pixel;
+       int64_t difference1;
+       int64_t difference2;
+};
+
+class MotionCVScanCache
+{
+public:
+       MotionCVScanCache(int x, int y, int64_t difference);
+       int x, y;
+       int64_t difference;
+};
+
+class MotionCVScanUnit : public LoadClient
+{
+public:
+       MotionCVScanUnit(MotionCVScan *server, MotionCVMain *plugin);
+       ~MotionCVScanUnit();
+
+       void process_package(LoadPackage *package);
+       int64_t get_cache(int x, int y);
+       void put_cache(int x, int y, int64_t difference);
+
+       MotionCVScan *server;
+       MotionCVMain *plugin;
+
+       ArrayList<MotionCVScanCache*> cache;
+       Mutex *cache_lock;
+};
+
+class MotionCVScan : public LoadServer
+{
+public:
+       MotionCVScan(MotionCVMain *plugin, 
+               int total_clients, 
+               int total_packages);
+       ~MotionCVScan();
+
+       friend class MotionCVScanUnit;
+
+       void init_packages();
+       LoadClient* new_client();
+       LoadPackage* new_package();
+
+// Invoke the motion engine for a search
+// Frame before motion
+       void scan_frame(VFrame *previous_frame,
+// Frame after motion
+               VFrame *current_frame);
+       int64_t get_cache(int x, int y);
+       void put_cache(int x, int y, int64_t difference);
+
+// Change between previous frame and current frame multiplied by 
+// OVERSAMPLE
+       int dx_result;
+       int dy_result;
+
+private:
+       VFrame *previous_frame;
+// Frame after motion
+       VFrame *current_frame;
+       MotionCVMain *plugin;
+
+       int skip;
+// For single block
+       int block_x1;
+       int block_x2;
+       int block_y1;
+       int block_y2;
+       int scan_x1;
+       int scan_y1;
+       int scan_x2;
+       int scan_y2;
+       int total_pixels;
+       int total_steps;
+       int subpixel;
+
+
+       ArrayList<MotionCVScanCache*> cache;
+       Mutex *cache_lock;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+class RotateCVScanPackage : public LoadPackage
+{
+public:
+       RotateCVScanPackage();
+       float angle;
+       int64_t difference;
+};
+
+class RotateCVScanCache
+{
+public:
+       RotateCVScanCache(float angle, int64_t difference);
+       float angle;
+       int64_t difference;
+};
+
+class RotateCVScanUnit : public LoadClient
+{
+public:
+       RotateCVScanUnit(RotateCVScan *server, MotionCVMain *plugin);
+       ~RotateCVScanUnit();
+
+       void process_package(LoadPackage *package);
+
+       RotateCVScan *server;
+       MotionCVMain *plugin;
+       AffineEngine *rotater;
+       VFrame *temp;
+};
+
+class RotateCVScan : public LoadServer
+{
+public:
+       RotateCVScan(MotionCVMain *plugin, 
+               int total_clients, 
+               int total_packages);
+       ~RotateCVScan();
+
+       friend class RotateCVScanUnit;
+
+       void init_packages();
+       LoadClient* new_client();
+       LoadPackage* new_package();
+
+// Invoke the motion engine for a search
+// Frame before rotation
+       float scan_frame(VFrame *previous_frame,
+// Frame after rotation
+               VFrame *current_frame,
+// Pivot
+               int block_x,
+               int block_y);
+       int64_t get_cache(float angle);
+       void put_cache(float angle, int64_t difference);
+
+
+// Angle result
+       float result;
+
+private:
+       VFrame *previous_frame;
+// Frame after motion
+       VFrame *current_frame;
+
+       MotionCVMain *plugin;
+       int skip;
+
+// Pivot
+       int block_x;
+       int block_y;
+// Block to rotate
+       int block_x1;
+       int block_x2;
+       int block_y1;
+       int block_y2;
+// Area to compare
+       int scan_x;
+       int scan_y;
+       int scan_w;
+       int scan_h;
+// Range of angles to compare
+       float scan_angle1, scan_angle2;
+       int total_steps;
+
+       ArrayList<RotateCVScanCache*> cache;
+       Mutex *cache_lock;
+};
+
+
+
+
+#endif
+
+
+
+
+
+
diff --git a/cinelerra-5.1/plugins/motion-cv/motionwindow-cv.C b/cinelerra-5.1/plugins/motion-cv/motionwindow-cv.C
new file mode 100644 (file)
index 0000000..e0e2b10
--- /dev/null
@@ -0,0 +1,1023 @@
+
+/*
+ * 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 "bcdisplayinfo.h"
+#include "clip.h"
+#include "language.h"
+#include "motion-cv.h"
+#include "motionwindow-cv.h"
+
+
+
+
+
+
+
+
+
+MotionCVWindow::MotionCVWindow(MotionCVMain *plugin)
+ : PluginClientWindow(plugin, 815, 650, 815, 650, 0)
+{
+       this->plugin = plugin; 
+}
+
+MotionCVWindow::~MotionCVWindow()
+{
+}
+
+void MotionCVWindow::create_objects()
+{
+       int x1 = 10, x = 10, y = 10;
+       int x2 = 410;
+       BC_Title *title;
+
+
+
+       add_subwindow(global = new MotionCVGlobal(plugin,
+               this,
+               x1,
+               y));
+
+       add_subwindow(rotate = new MotionCVRotate(plugin,
+               this,
+               x2,
+               y));
+       y += 50;
+
+       add_subwindow(title = new BC_Title(x1, 
+               y, 
+               _("Translation search radius:\n(W/H Percent of image)")));
+       add_subwindow(global_range_w = new GlobalRange(plugin, 
+               x1 + title->get_w() + 10, 
+               y,
+               &plugin->config.global_range_w));
+       add_subwindow(global_range_h = new GlobalRange(plugin, 
+               x1 + title->get_w() + 30 + global_range_w->get_w(),
+               y,
+               &plugin->config.global_range_h));
+
+       add_subwindow(title = new BC_Title(x2, 
+               y, 
+               _("Rotation search radius:\n(Degrees)")));
+       add_subwindow(rotation_range = new RotationRange(plugin, 
+               x2 + title->get_w() + 10, 
+               y));
+
+       y += 50;
+       add_subwindow(title = new BC_Title(x1, 
+               y, 
+               _("Translation block size:\n(W/H Percent of image)")));
+       add_subwindow(global_block_w = new BlockSize(plugin, 
+               x1 + title->get_w() + 10, 
+               y,
+               &plugin->config.global_block_w));
+       add_subwindow(global_block_h = new BlockSize(plugin, 
+               x1 + title->get_w() + 30 + global_block_w->get_w(),
+               y,
+               &plugin->config.global_block_h));
+
+       add_subwindow(title = new BC_Title(x2, 
+               y, 
+               _("Rotation block size:\n(W/H Percent of image)")));
+       add_subwindow(rotation_block_w = new BlockSize(plugin, 
+               x2 + title->get_w() + 10, 
+               y,
+               &plugin->config.rotation_block_w));
+       add_subwindow(rotation_block_h = new BlockSize(plugin, 
+               x2 + title->get_w() + 30 + rotation_block_w->get_w(),
+               y,
+               &plugin->config.rotation_block_h));
+
+       y += 50;
+       add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
+       add_subwindow(global_search_positions = new GlobalSearchPositions(plugin, 
+               x1 + title->get_w() + 10, 
+               y, 
+               80));
+       global_search_positions->create_objects();
+
+       add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
+       add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin, 
+               x2 + title->get_w() + 10, 
+               y, 
+               80));
+       rotation_search_positions->create_objects();
+
+       y += 50;
+       add_subwindow(title = new BC_Title(x, y, _("Translation direction:")));
+       add_subwindow(mode3 = new Mode3(plugin, 
+               this, 
+               x + title->get_w() + 10, 
+               y));
+       mode3->create_objects();
+
+       y += 40;
+       add_subwindow(title = new BC_Title(x, y + 10, _("Block X:")));
+       add_subwindow(block_x = new MotionCVBlockX(plugin, 
+               this, 
+               x + title->get_w() + 10, 
+               y));
+       add_subwindow(block_x_text = new MotionCVBlockXText(plugin, 
+               this, 
+               x + title->get_w() + 10 + block_x->get_w() + 10, 
+               y + 10));
+
+       y += 40;
+       add_subwindow(title = new BC_Title(x, y + 10, _("Block Y:")));
+       add_subwindow(block_y = new MotionCVBlockY(plugin, 
+               this, 
+               x + title->get_w() + 10, 
+               y));
+       add_subwindow(block_y_text = new MotionCVBlockYText(plugin, 
+               this, 
+               x + title->get_w() + 10 + block_y->get_w() + 10, 
+               y + 10));
+
+       y += 50;
+       add_subwindow(title = new BC_Title(x, y + 10, _("Maximum absolute offset:")));
+       add_subwindow(magnitude = new MotionCVMagnitude(plugin, 
+               x + title->get_w() + 10, 
+               y));
+
+       y += 40;
+       add_subwindow(title = new BC_Title(x, y + 10, _("Settling speed:")));
+       add_subwindow(return_speed = new MotionCVReturnSpeed(plugin,
+               x + title->get_w() + 10, 
+               y));
+
+
+
+       y += 40;
+       add_subwindow(vectors = new MotionCVDrawVectors(plugin,
+               this,
+               x,
+               y));
+
+       add_subwindow(title = new BC_Title(x2, y, _("Tracking file:")));
+       add_subwindow(tracking_file = new MotionCVTrackingFile(plugin,
+               plugin->config.tracking_file, this, x2+title->get_w() + 20, y));
+
+       y += 40;
+       add_subwindow(track_single = new TrackSingleFrame(plugin, 
+               this,
+               x, 
+               y));
+       add_subwindow(title = new BC_Title(x + track_single->get_w() + 20, 
+               y, 
+               _("Frame number:")));
+       add_subwindow(track_frame_number = new TrackFrameNumber(plugin, 
+               this,
+               x + track_single->get_w() + title->get_w() + 20, 
+               y));
+       add_subwindow(addtrackedframeoffset = new AddTrackedFrameOffset(plugin,
+               this,
+               x + track_single->get_w() + title->get_w() + 30,
+               y + track_single->get_h()));
+
+
+       y += 20;
+       add_subwindow(track_previous = new TrackPreviousFrame(plugin, 
+               this,
+               x, 
+               y));
+
+       y += 20;
+       add_subwindow(previous_same = new PreviousFrameSameBlock(plugin, 
+               this,
+               x, 
+               y));
+
+       y += 40;
+       //int y1 = y;
+       add_subwindow(title = new BC_Title(x, y, _("Master layer:")));
+       add_subwindow(master_layer = new MasterLayer(plugin, 
+               this,
+               x + title->get_w() + 10, 
+               y));
+       master_layer->create_objects();
+       y += 30;
+
+
+       add_subwindow(title = new BC_Title(x, y, _("Action:")));
+       add_subwindow(mode1 = new Mode1(plugin, 
+               this,
+               x + title->get_w() + 10, 
+               y));
+       mode1->create_objects();
+       y += 30;
+
+
+
+
+       add_subwindow(title = new BC_Title(x, y, _("Calculation:")));
+       add_subwindow(mode2 = new Mode2(plugin, 
+               this, 
+               x + title->get_w() + 10, 
+               y));
+       mode2->create_objects();
+
+
+
+       show_window(1);
+}
+
+void MotionCVWindow::update_mode()
+{
+       global_range_w->update(plugin->config.global_range_w,
+               MIN_RADIUS,
+               MAX_RADIUS);
+       global_range_h->update(plugin->config.global_range_h,
+               MIN_RADIUS,
+               MAX_RADIUS);
+       rotation_range->update(plugin->config.rotation_range,
+               MIN_ROTATION,
+               MAX_ROTATION);
+       vectors->update(plugin->config.draw_vectors);
+       tracking_file->update(plugin->config.tracking_file);
+       global->update(plugin->config.global);
+       rotate->update(plugin->config.rotate);
+       addtrackedframeoffset->update(plugin->config.addtrackedframeoffset);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+GlobalRange::GlobalRange(MotionCVMain *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 GlobalRange::handle_event()
+{
+       *value = (int)get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+RotationRange::RotationRange(MotionCVMain *plugin, 
+       int x, 
+       int y)
+ : BC_IPot(x, 
+               y, 
+               (int64_t)plugin->config.rotation_range,
+               (int64_t)MIN_ROTATION,
+               (int64_t)MAX_ROTATION)
+{
+       this->plugin = plugin;
+}
+
+
+int RotationRange::handle_event()
+{
+       plugin->config.rotation_range = (int)get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+BlockSize::BlockSize(MotionCVMain *plugin, 
+       int x, 
+       int y,
+       int *value)
+ : BC_IPot(x, 
+               y, 
+               (int64_t)*value,
+               (int64_t)MIN_BLOCK,
+               (int64_t)MAX_BLOCK)
+{
+       this->plugin = plugin;
+       this->value = value;
+}
+
+
+int BlockSize::handle_event()
+{
+       *value = (int)get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+GlobalSearchPositions::GlobalSearchPositions(MotionCVMain *plugin, 
+       int x, 
+       int y,
+       int w)
+ : BC_PopupMenu(x,
+       y,
+       w,
+       "",
+       1)
+{
+       this->plugin = plugin;
+}
+void GlobalSearchPositions::create_objects()
+{
+       add_item(new BC_MenuItem("64"));
+       add_item(new BC_MenuItem("128"));
+       add_item(new BC_MenuItem("256"));
+       add_item(new BC_MenuItem("512"));
+       add_item(new BC_MenuItem("1024"));
+       add_item(new BC_MenuItem("2048"));
+       add_item(new BC_MenuItem("4096"));
+       add_item(new BC_MenuItem("8192"));
+       add_item(new BC_MenuItem("16384"));
+       add_item(new BC_MenuItem("32768"));
+       add_item(new BC_MenuItem("65536"));
+       add_item(new BC_MenuItem("131072"));
+       char string[BCTEXTLEN];
+       sprintf(string, "%d", plugin->config.global_positions);
+       set_text(string);
+}
+
+int GlobalSearchPositions::handle_event()
+{
+       plugin->config.global_positions = atoi(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+RotationSearchPositions::RotationSearchPositions(MotionCVMain *plugin, 
+       int x, 
+       int y,
+       int w)
+ : BC_PopupMenu(x,
+       y,
+       w,
+       "",
+       1)
+{
+       this->plugin = plugin;
+}
+void RotationSearchPositions::create_objects()
+{
+       add_item(new BC_MenuItem("4"));
+       add_item(new BC_MenuItem("8"));
+       add_item(new BC_MenuItem("16"));
+       add_item(new BC_MenuItem("32"));
+       char string[BCTEXTLEN];
+       sprintf(string, "%d", plugin->config.rotate_positions);
+       set_text(string);
+}
+
+int RotationSearchPositions::handle_event()
+{
+       plugin->config.rotate_positions = atoi(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+MotionCVMagnitude::MotionCVMagnitude(MotionCVMain *plugin, 
+       int x, 
+       int y)
+ : BC_IPot(x, 
+               y, 
+               (int64_t)plugin->config.magnitude,
+               (int64_t)0,
+               (int64_t)100)
+{
+       this->plugin = plugin;
+}
+
+int MotionCVMagnitude::handle_event()
+{
+       plugin->config.magnitude = (int)get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+MotionCVReturnSpeed::MotionCVReturnSpeed(MotionCVMain *plugin, 
+       int x, 
+       int y)
+ : BC_IPot(x, 
+               y, 
+               (int64_t)plugin->config.return_speed,
+               (int64_t)0,
+               (int64_t)100)
+{
+       this->plugin = plugin;
+}
+
+int MotionCVReturnSpeed::handle_event()
+{
+       plugin->config.return_speed = (int)get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+AddTrackedFrameOffset::AddTrackedFrameOffset(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_CheckBox(x, 
+       y, 
+       plugin->config.addtrackedframeoffset,
+       _("Add (loaded) offset from tracked frame"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int AddTrackedFrameOffset::handle_event()
+{
+       plugin->config.addtrackedframeoffset = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+MotionCVTrackingFile::MotionCVTrackingFile(MotionCVMain *plugin,
+       const char *filename, MotionCVWindow *gui, int x, int y)
+ : BC_TextBox(x, y, 250, 1, filename)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+};
+
+int MotionCVTrackingFile::handle_event()
+{
+       strcpy(plugin->config.tracking_file, get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+MotionCVGlobal::MotionCVGlobal(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_CheckBox(x, 
+       y, 
+       plugin->config.global,
+       _("Track translation"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int MotionCVGlobal::handle_event()
+{
+       plugin->config.global = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+MotionCVRotate::MotionCVRotate(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_CheckBox(x, 
+       y, 
+       plugin->config.rotate,
+       _("Track rotation"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int MotionCVRotate::handle_event()
+{
+       plugin->config.rotate = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+MotionCVBlockX::MotionCVBlockX(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_FPot(x,
+       y,
+       plugin->config.block_x,
+       (float)0, 
+       (float)100)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int MotionCVBlockX::handle_event()
+{
+       plugin->config.block_x = get_value();
+       gui->block_x_text->update((float)plugin->config.block_x);
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+MotionCVBlockY::MotionCVBlockY(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_FPot(x,
+       y,
+       (float)plugin->config.block_y,
+       (float)0, 
+       (float)100)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int MotionCVBlockY::handle_event()
+{
+       plugin->config.block_y = get_value();
+       gui->block_y_text->update((float)plugin->config.block_y);
+       plugin->send_configure_change();
+       return 1;
+}
+
+MotionCVBlockXText::MotionCVBlockXText(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_TextBox(x,
+       y,
+       75,
+       1,
+       (float)plugin->config.block_x)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+       set_precision(4);
+}
+
+int MotionCVBlockXText::handle_event()
+{
+       plugin->config.block_x = atof(get_text());
+       gui->block_x->update(plugin->config.block_x);
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+MotionCVBlockYText::MotionCVBlockYText(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_TextBox(x,
+       y,
+       75,
+       1,
+       (float)plugin->config.block_y)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+       set_precision(4);
+}
+
+int MotionCVBlockYText::handle_event()
+{
+       plugin->config.block_y = atof(get_text());
+       gui->block_y->update(plugin->config.block_y);
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+MotionCVDrawVectors::MotionCVDrawVectors(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_CheckBox(x,
+       y, 
+       plugin->config.draw_vectors,
+       _("Draw vectors"))
+{
+       this->gui = gui;
+       this->plugin = plugin;
+}
+
+int MotionCVDrawVectors::handle_event()
+{
+       plugin->config.draw_vectors = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+TrackSingleFrame::TrackSingleFrame(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_Radial(x, 
+       y, 
+       plugin->config.mode3 == MotionCVConfig::TRACK_SINGLE, 
+       _("Track single frame"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int TrackSingleFrame::handle_event()
+{
+       plugin->config.mode3 = MotionCVConfig::TRACK_SINGLE;
+       gui->track_previous->update(0);
+       gui->previous_same->update(0);
+       gui->track_frame_number->enable();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+TrackFrameNumber::TrackFrameNumber(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_TextBox(x, y, 100, 1, plugin->config.track_frame)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+       if(plugin->config.mode3 != MotionCVConfig::TRACK_SINGLE) disable();
+}
+
+int TrackFrameNumber::handle_event()
+{
+       plugin->config.track_frame = atol(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+TrackPreviousFrame::TrackPreviousFrame(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_Radial(x, 
+       y, 
+       plugin->config.mode3 == MotionCVConfig::TRACK_PREVIOUS, 
+       _("Track previous frame"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+int TrackPreviousFrame::handle_event()
+{
+       plugin->config.mode3 = MotionCVConfig::TRACK_PREVIOUS;
+       gui->track_single->update(0);
+       gui->previous_same->update(0);
+       gui->track_frame_number->disable();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+PreviousFrameSameBlock::PreviousFrameSameBlock(MotionCVMain *plugin, 
+       MotionCVWindow *gui,
+       int x, 
+       int y)
+ : BC_Radial(x, 
+       y, 
+       plugin->config.mode3 == MotionCVConfig::PREVIOUS_SAME_BLOCK, 
+       _("Previous frame same block"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+int PreviousFrameSameBlock::handle_event()
+{
+       plugin->config.mode3 = MotionCVConfig::PREVIOUS_SAME_BLOCK;
+       gui->track_single->update(0);
+       gui->track_previous->update(0);
+       gui->track_frame_number->disable();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+MasterLayer::MasterLayer(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, calculate_w(gui),
+               to_text(plugin->config.bottom_is_master))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int MasterLayer::handle_event()
+{
+       plugin->config.bottom_is_master = from_text(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+void MasterLayer::create_objects()
+{
+       add_item(new BC_MenuItem(to_text(0)));
+       add_item(new BC_MenuItem(to_text(1)));
+}
+
+int MasterLayer::from_text(char *text)
+{
+       if(!strcmp(text, _("Top"))) return 0;
+       return 1;
+}
+
+const char* MasterLayer::to_text(int mode)
+{
+       return mode ? _("Bottom") : _("Top");
+}
+
+int MasterLayer::calculate_w(MotionCVWindow *gui)
+{
+       int result = 0;
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1)));
+       return result + 50;
+}
+
+
+
+
+
+
+
+
+Mode1::Mode1(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, calculate_w(gui),
+               to_text(plugin->config.mode1))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int Mode1::handle_event()
+{
+       plugin->config.mode1 = from_text(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+void Mode1::create_objects()
+{
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::TRACK)));
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::TRACK_PIXEL)));
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::STABILIZE)));
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::STABILIZE_PIXEL)));
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::NOTHING)));
+}
+
+int Mode1::from_text(char *text)
+{
+       if(!strcmp(text, _("Track Subpixel"))) return MotionCVConfig::TRACK;
+       if(!strcmp(text, _("Track Pixel"))) return MotionCVConfig::TRACK_PIXEL;
+       if(!strcmp(text, _("Stabilize Subpixel"))) return MotionCVConfig::STABILIZE;
+       if(!strcmp(text, _("Stabilize Pixel"))) return MotionCVConfig::STABILIZE_PIXEL;
+       //if(!strcmp(text, _("Do Nothing"))) return MotionCVConfig::NOTHING;
+       return MotionCVConfig::NOTHING;
+}
+
+const char* Mode1::to_text(int mode)
+{
+       switch(mode) {
+       case MotionCVConfig::TRACK:     return _("Track Subpixel");
+       case MotionCVConfig::TRACK_PIXEL:       return _("Track Pixel");
+       case MotionCVConfig::STABILIZE: return _("Stabilize Subpixel");
+       case MotionCVConfig::STABILIZE_PIXEL: return _("Stabilize Pixel");
+       case MotionCVConfig::NOTHING:   return _("Do Nothing");
+       }
+       return "";
+}
+
+int Mode1::calculate_w(MotionCVWindow *gui)
+{
+       int result = 0;
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::TRACK)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::TRACK_PIXEL)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::STABILIZE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::STABILIZE_PIXEL)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::NOTHING)));
+       return result + 50;
+}
+
+
+
+
+
+Mode2::Mode2(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, calculate_w(gui),
+               to_text(plugin->config.mode2))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int Mode2::handle_event()
+{
+       plugin->config.mode2 = from_text(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+void Mode2::create_objects()
+{
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::NO_CALCULATE)));
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::RECALCULATE)));
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::SAVE)));
+       add_item(new BC_MenuItem(to_text(MotionCVConfig::LOAD)));
+}
+
+int Mode2::from_text(char *text)
+{
+       if(!strcmp(text, _("Recalculate"))) return MotionCVConfig::RECALCULATE;
+       if(!strcmp(text, _("Save coords to tracking file"))) return MotionCVConfig::SAVE;
+       if(!strcmp(text, _("Load coords from tracking file"))) return MotionCVConfig::LOAD;
+       //if(!strcmp(text, _("Don't Calculate"))) return MotionCVConfig::NO_CALCULATE;
+       return MotionCVConfig::NO_CALCULATE;
+}
+
+const char* Mode2::to_text(int mode)
+{
+       switch(mode) {
+       case MotionCVConfig::NO_CALCULATE: return _("Don't Calculate");
+       case MotionCVConfig::RECALCULATE: return _("Recalculate");
+       case MotionCVConfig::SAVE: return _("Save coords to tracking file");
+       case MotionCVConfig::LOAD: return _("Load coords from tracking file");
+       }
+       return "";
+}
+
+int Mode2::calculate_w(MotionCVWindow *gui)
+{
+       int result = 0;
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::NO_CALCULATE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::RECALCULATE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::SAVE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::LOAD)));
+       return result + 50;
+}
+
+
+
+
+
+
+
+
+
+
+Mode3::Mode3(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, calculate_w(gui),
+               to_text(plugin->config.horizontal_only, plugin->config.vertical_only))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int Mode3::handle_event()
+{
+       from_text(&plugin->config.horizontal_only, &plugin->config.vertical_only, get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+void Mode3::create_objects()
+{
+       add_item(new BC_MenuItem(to_text(1, 0)));
+       add_item(new BC_MenuItem(to_text(0, 1)));
+       add_item(new BC_MenuItem(to_text(0, 0)));
+}
+
+void Mode3::from_text(int *horizontal_only, int *vertical_only, char *text)
+{
+       *horizontal_only = 0;
+       *vertical_only = 0;
+       if(!strcmp(text, to_text(1, 0))) *horizontal_only = 1;
+       if(!strcmp(text, to_text(0, 1))) *vertical_only = 1;
+}
+
+const char* Mode3::to_text(int horizontal_only, int vertical_only)
+{
+       if(horizontal_only) return _("Horizontal only");
+       if(vertical_only) return _("Vertical only");
+       return _("Both");
+}
+
+int Mode3::calculate_w(MotionCVWindow *gui)
+{
+       int result = 0;
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1, 0)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 1)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 0)));
+       return result + 50;
+}
+
diff --git a/cinelerra-5.1/plugins/motion-cv/motionwindow-cv.h b/cinelerra-5.1/plugins/motion-cv/motionwindow-cv.h
new file mode 100644 (file)
index 0000000..c3cd5f8
--- /dev/null
@@ -0,0 +1,360 @@
+
+/*
+ * 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 "guicast.h"
+
+class MotionCVMain;
+class MotionCVWindow;
+class MotionCVScan;
+class RotateCVScan;
+
+class MasterLayer : public BC_PopupMenu
+{
+public:
+       MasterLayer(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionCVWindow *gui);
+       static int from_text(char *text);
+       static const char* to_text(int mode);
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class Mode1 : public BC_PopupMenu
+{
+public:
+       Mode1(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionCVWindow *gui);
+       static int from_text(char *text);
+       static const char* to_text(int mode);
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class Mode2 : public BC_PopupMenu
+{
+public:
+       Mode2(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionCVWindow *gui);
+       static int from_text(char *text);
+       static const char* to_text(int mode);
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class Mode3 : public BC_PopupMenu
+{
+public:
+       Mode3(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionCVWindow *gui);
+       static void from_text(int *horizontal_only, int *vertical_only, char *text);
+       static const char* to_text(int horizontal_only, int vertical_only);
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+
+class TrackSingleFrame : public BC_Radial
+{
+public:
+       TrackSingleFrame(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class TrackFrameNumber : public BC_TextBox
+{
+public:
+       TrackFrameNumber(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class TrackPreviousFrame : public BC_Radial
+{
+public:
+       TrackPreviousFrame(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class PreviousFrameSameBlock : public BC_Radial
+{
+public:
+       PreviousFrameSameBlock(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class GlobalRange : public BC_IPot
+{
+public:
+       GlobalRange(MotionCVMain *plugin, 
+               int x, 
+               int y,
+               int *value);
+       int handle_event();
+       MotionCVMain *plugin;
+       int *value;
+};
+
+class RotationRange : public BC_IPot
+{
+public:
+       RotationRange(MotionCVMain *plugin, 
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+};
+
+class BlockSize : public BC_IPot
+{
+public:
+       BlockSize(MotionCVMain *plugin, 
+               int x, 
+               int y,
+               int *value);
+       int handle_event();
+       MotionCVMain *plugin;
+       int *value;
+};
+
+class MotionCVBlockX : public BC_FPot
+{
+public:
+       MotionCVBlockX(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVWindow *gui;
+       MotionCVMain *plugin;
+};
+
+class MotionCVBlockY : public BC_FPot
+{
+public:
+       MotionCVBlockY(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVWindow *gui;
+       MotionCVMain *plugin;
+};
+
+class MotionCVBlockXText : public BC_TextBox
+{
+public:
+       MotionCVBlockXText(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVWindow *gui;
+       MotionCVMain *plugin;
+};
+
+class MotionCVBlockYText : public BC_TextBox
+{
+public:
+       MotionCVBlockYText(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVWindow *gui;
+       MotionCVMain *plugin;
+};
+
+class GlobalSearchPositions : public BC_PopupMenu
+{
+public:
+       GlobalSearchPositions(MotionCVMain *plugin, 
+               int x, 
+               int y,
+               int w);
+       void create_objects();
+       int handle_event();
+       MotionCVMain *plugin;
+};
+
+class RotationSearchPositions : public BC_PopupMenu
+{
+public:
+       RotationSearchPositions(MotionCVMain *plugin, 
+               int x, 
+               int y,
+               int w);
+       void create_objects();
+       int handle_event();
+       MotionCVMain *plugin;
+};
+
+class MotionCVMagnitude : public BC_IPot
+{
+public:
+       MotionCVMagnitude(MotionCVMain *plugin, 
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+};
+
+class MotionCVReturnSpeed : public BC_IPot
+{
+public:
+       MotionCVReturnSpeed(MotionCVMain *plugin, 
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+};
+
+
+
+class MotionCVDrawVectors : public BC_CheckBox
+{
+public:
+       MotionCVDrawVectors(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class AddTrackedFrameOffset : public BC_CheckBox
+{
+public:
+       AddTrackedFrameOffset(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVWindow *gui;
+       MotionCVMain *plugin;
+};
+
+class MotionCVTrackingFile : public BC_TextBox
+{
+public:
+       MotionCVTrackingFile(MotionCVMain *plugin, const char *filename,
+               MotionCVWindow *gui, int x, int y);
+       int handle_event();
+       MotionCVMain *plugin;
+       MotionCVWindow *gui;
+};
+
+class MotionCVGlobal : public BC_CheckBox
+{
+public:
+       MotionCVGlobal(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVWindow *gui;
+       MotionCVMain *plugin;
+};
+
+class MotionCVRotate : public BC_CheckBox
+{
+public:
+       MotionCVRotate(MotionCVMain *plugin, 
+               MotionCVWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionCVWindow *gui;
+       MotionCVMain *plugin;
+};
+
+
+
+class MotionCVWindow : public PluginClientWindow
+{
+public:
+       MotionCVWindow(MotionCVMain *plugin);
+       ~MotionCVWindow();
+
+       void create_objects();
+       void update_mode();
+       char* get_radius_title();
+
+       GlobalRange *global_range_w;
+       GlobalRange *global_range_h;
+       RotationRange *rotation_range;
+       BlockSize *global_block_w;
+       BlockSize *global_block_h;
+       BlockSize *rotation_block_w;
+       BlockSize *rotation_block_h;
+       MotionCVBlockX *block_x;
+       MotionCVBlockY *block_y;
+       MotionCVBlockXText *block_x_text;
+       MotionCVBlockYText *block_y_text;
+       GlobalSearchPositions *global_search_positions;
+       RotationSearchPositions *rotation_search_positions;
+       MotionCVMagnitude *magnitude;
+       MotionCVReturnSpeed *return_speed;
+       Mode1 *mode1;
+       MotionCVDrawVectors *vectors;
+       MotionCVTrackingFile *tracking_file;
+       MotionCVGlobal *global;
+       MotionCVRotate *rotate;
+       AddTrackedFrameOffset *addtrackedframeoffset;
+       TrackSingleFrame *track_single;
+       TrackFrameNumber *track_frame_number;
+       TrackPreviousFrame *track_previous;
+       PreviousFrameSameBlock *previous_same;
+       MasterLayer *master_layer;
+       Mode2 *mode2;
+       Mode3 *mode3;
+
+       MotionCVMain *plugin;
+};
+
+
diff --git a/cinelerra-5.1/plugins/motion-cv/picon.png b/cinelerra-5.1/plugins/motion-cv/picon.png
new file mode 100644 (file)
index 0000000..a854b23
Binary files /dev/null and b/cinelerra-5.1/plugins/motion-cv/picon.png differ
diff --git a/cinelerra-5.1/plugins/motion-hv/Makefile b/cinelerra-5.1/plugins/motion-hv/Makefile
new file mode 100644 (file)
index 0000000..695fd5e
--- /dev/null
@@ -0,0 +1,14 @@
+include ../../plugin_defs
+
+OBJS := \
+       $(OBJDIR)/motion-hv.o \
+       $(OBJDIR)/motionscan-hv.o \
+       $(OBJDIR)/motionwindow-hv.o
+
+PLUGIN = motion-hv
+
+include ../../plugin_config
+
+$(OBJDIR)/motion-hv.o: motion-hv.C
+$(OBJDIR)/motionscan-hv.o: motionscan-hv.C
+$(OBJDIR)/motionwindow-hv.o: motionwindow-hv.C
similarity index 60%
rename from cinelerra-5.1/plugins/motion.new/motion.C
rename to cinelerra-5.1/plugins/motion-hv/motion-hv.C
index 81d9705b93ff4c1fb36c5d9bb245090167c00fd7..3b0b128ab7e500e31baf8eab232b93f6ea6f4480 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 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
@@ -27,9 +27,9 @@
 #include "filexml.h"
 #include "keyframe.h"
 #include "language.h"
-#include "motion.h"
-#include "motionscan.h"
-#include "motionwindow.h"
+#include "motion-hv.h"
+#include "motionscan-hv.h"
+#include "motionwindow-hv.h"
 #include "mutex.h"
 #include "overlayframe.h"
 #include "rotateframe.h"
@@ -39,7 +39,7 @@
 #include <errno.h>
 #include <unistd.h>
 
-REGISTER_PLUGIN(MotionMain)
+REGISTER_PLUGIN(MotionHVMain)
 
 #undef DEBUG
 
@@ -49,7 +49,7 @@ REGISTER_PLUGIN(MotionMain)
 
 
 
-MotionConfig::MotionConfig()
+MotionHVConfig::MotionHVConfig()
 {
        global_range_w = 5;
        global_range_h = 5;
@@ -58,29 +58,29 @@ MotionConfig::MotionConfig()
        block_count = 1;
        global_block_w = MIN_BLOCK;
        global_block_h = MIN_BLOCK;
-       rotation_block_w = MIN_BLOCK;
-       rotation_block_h = MIN_BLOCK;
+//     rotation_block_w = MIN_BLOCK;
+//     rotation_block_h = MIN_BLOCK;
        block_x = 50;
        block_y = 50;
-       global_positions = 256;
-       rotate_positions = 4;
+//     global_positions = 256;
+//     rotate_positions = 4;
        magnitude = 100;
        rotate_magnitude = 90;
        return_speed = 0;
        rotate_return_speed = 0;
-       action_type = MotionScan::STABILIZE;
-       global = 1;
+       action_type = MotionHVScan::STABILIZE;
+//     global = 1;
        rotate = 1;
-       tracking_type = MotionScan::NO_CALCULATE;
+       tracking_type = MotionHVScan::NO_CALCULATE;
        draw_vectors = 1;
-       tracking_object = MotionScan::TRACK_SINGLE;
+       tracking_object = MotionHVScan::TRACK_SINGLE;
        track_frame = 0;
        bottom_is_master = 1;
        horizontal_only = 0;
        vertical_only = 0;
 }
 
-void MotionConfig::boundaries()
+void MotionHVConfig::boundaries()
 {
        CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS);
        CLAMP(global_range_h, MIN_RADIUS, MAX_RADIUS);
@@ -89,29 +89,29 @@ void MotionConfig::boundaries()
        CLAMP(block_count, MIN_BLOCKS, MAX_BLOCKS);
        CLAMP(global_block_w, MIN_BLOCK, MAX_BLOCK);
        CLAMP(global_block_h, MIN_BLOCK, MAX_BLOCK);
-       CLAMP(rotation_block_w, MIN_BLOCK, MAX_BLOCK);
-       CLAMP(rotation_block_h, MIN_BLOCK, MAX_BLOCK);
+//     CLAMP(rotation_block_w, MIN_BLOCK, MAX_BLOCK);
+//     CLAMP(rotation_block_h, MIN_BLOCK, MAX_BLOCK);
 }
 
-int MotionConfig::equivalent(MotionConfig &that)
+int MotionHVConfig::equivalent(MotionHVConfig &that)
 {
        return global_range_w == that.global_range_w &&
                global_range_h == that.global_range_h &&
                rotation_range == that.rotation_range &&
                rotation_center == that.rotation_center &&
                action_type == that.action_type &&
-               global == that.global &&
+//             global == that.global &&
                rotate == that.rotate &&
                draw_vectors == that.draw_vectors &&
                block_count == that.block_count &&
                global_block_w == that.global_block_w &&
                global_block_h == that.global_block_h &&
-               rotation_block_w == that.rotation_block_w &&
-               rotation_block_h == that.rotation_block_h &&
+//             rotation_block_w == that.rotation_block_w &&
+//             rotation_block_h == that.rotation_block_h &&
                EQUIV(block_x, that.block_x) &&
                EQUIV(block_y, that.block_y) &&
-               global_positions == that.global_positions &&
-               rotate_positions == that.rotate_positions &&
+//             global_positions == that.global_positions &&
+//             rotate_positions == that.rotate_positions &&
                magnitude == that.magnitude &&
                return_speed == that.return_speed &&
                rotate_return_speed == that.rotate_return_speed &&
@@ -123,26 +123,26 @@ int MotionConfig::equivalent(MotionConfig &that)
                vertical_only == that.vertical_only;
 }
 
-void MotionConfig::copy_from(MotionConfig &that)
+void MotionHVConfig::copy_from(MotionHVConfig &that)
 {
        global_range_w = that.global_range_w;
        global_range_h = that.global_range_h;
        rotation_range = that.rotation_range;
        rotation_center = that.rotation_center;
        action_type = that.action_type;
-       global = that.global;
+//     global = that.global;
        rotate = that.rotate;
        tracking_type = that.tracking_type;
        draw_vectors = that.draw_vectors;
        block_count = that.block_count;
        block_x = that.block_x;
        block_y = that.block_y;
-       global_positions = that.global_positions;
-       rotate_positions = that.rotate_positions;
+//     global_positions = that.global_positions;
+//     rotate_positions = that.rotate_positions;
        global_block_w = that.global_block_w;
        global_block_h = that.global_block_h;
-       rotation_block_w = that.rotation_block_w;
-       rotation_block_h = that.rotation_block_h;
+//     rotation_block_w = that.rotation_block_w;
+//     rotation_block_h = that.rotation_block_h;
        magnitude = that.magnitude;
        return_speed = that.return_speed;
        rotate_magnitude = that.rotate_magnitude;
@@ -154,14 +154,14 @@ void MotionConfig::copy_from(MotionConfig &that)
        vertical_only = that.vertical_only;
 }
 
-void MotionConfig::interpolate(MotionConfig &prev,
-       MotionConfig &next,
+void MotionHVConfig::interpolate(MotionHVConfig &prev,
+       MotionHVConfig &next,
        int64_t prev_frame,
        int64_t next_frame,
        int64_t current_frame)
 {
-       double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
-       double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+       //double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
+       //double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
        this->block_x = prev.block_x;
        this->block_y = prev.block_y;
        global_range_w = prev.global_range_w;
@@ -169,17 +169,17 @@ void MotionConfig::interpolate(MotionConfig &prev,
        rotation_range = prev.rotation_range;
        rotation_center = prev.rotation_center;
        action_type = prev.action_type;
-       global = prev.global;
+//     global = prev.global;
        rotate = prev.rotate;
        tracking_type = prev.tracking_type;
        draw_vectors = prev.draw_vectors;
        block_count = prev.block_count;
-       global_positions = prev.global_positions;
-       rotate_positions = prev.rotate_positions;
+//     global_positions = prev.global_positions;
+//     rotate_positions = prev.rotate_positions;
        global_block_w = prev.global_block_w;
        global_block_h = prev.global_block_h;
-       rotation_block_w = prev.rotation_block_w;
-       rotation_block_h = prev.rotation_block_h;
+//     rotation_block_w = prev.rotation_block_w;
+//     rotation_block_h = prev.rotation_block_h;
        magnitude = prev.magnitude;
        return_speed = prev.return_speed;
        rotate_magnitude = prev.rotate_magnitude;
@@ -209,12 +209,12 @@ void MotionConfig::interpolate(MotionConfig &prev,
 
 
 
-MotionMain::MotionMain(PluginServer *server)
+MotionHVMain::MotionHVMain(PluginServer *server)
  : PluginVClient(server)
 {
        engine = 0;
        rotate_engine = 0;
-       motion_rotate = 0;
+//     motion_rotate = 0;
        total_dx = 0;
        total_dy = 0;
        total_angle = 0;
@@ -235,7 +235,7 @@ MotionMain::MotionMain(PluginServer *server)
        rotate_target_dst = 0;
 }
 
-MotionMain::~MotionMain()
+MotionHVMain::~MotionHVMain()
 {
 
        delete engine;
@@ -243,7 +243,7 @@ MotionMain::~MotionMain()
        delete [] search_area;
        delete temp_frame;
        delete rotate_engine;
-       delete motion_rotate;
+//     delete motion_rotate;
 
 
        delete prev_global_ref;
@@ -257,67 +257,67 @@ MotionMain::~MotionMain()
        delete rotate_target_dst;
 }
 
-const char* MotionMain::plugin_title() { return _("Motion"); }
-int MotionMain::is_realtime() { return 1; }
-int MotionMain::is_multichannel() { return 1; }
+const char* MotionHVMain::plugin_title() { return _("MotionHV"); }
+int MotionHVMain::is_realtime() { return 1; }
+int MotionHVMain::is_multichannel() { return 1; }
 
 
-NEW_WINDOW_MACRO(MotionMain, MotionWindow)
+NEW_WINDOW_MACRO(MotionHVMain, MotionHVWindow)
 
-LOAD_CONFIGURATION_MACRO(MotionMain, MotionConfig)
+LOAD_CONFIGURATION_MACRO(MotionHVMain, MotionHVConfig)
 
 
 
-void MotionMain::update_gui()
+void MotionHVMain::update_gui()
 {
        if(thread)
        {
                if(load_configuration())
                {
-                       thread->window->lock_window("MotionMain::update_gui");
-
-                       char string[BCTEXTLEN];
-                       sprintf(string, "%d", config.global_positions);
-                       ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
-                       sprintf(string, "%d", config.rotate_positions);
-                       ((MotionWindow*)thread->window)->rotation_search_positions->set_text(string);
-
-                       ((MotionWindow*)thread->window)->global_block_w->update(config.global_block_w);
-                       ((MotionWindow*)thread->window)->global_block_h->update(config.global_block_h);
-                       ((MotionWindow*)thread->window)->rotation_block_w->update(config.rotation_block_w);
-                       ((MotionWindow*)thread->window)->rotation_block_h->update(config.rotation_block_h);
-                       ((MotionWindow*)thread->window)->block_x->update(config.block_x);
-                       ((MotionWindow*)thread->window)->block_y->update(config.block_y);
-                       ((MotionWindow*)thread->window)->block_x_text->update((float)config.block_x);
-                       ((MotionWindow*)thread->window)->block_y_text->update((float)config.block_y);
-                       ((MotionWindow*)thread->window)->magnitude->update(config.magnitude);
-                       ((MotionWindow*)thread->window)->return_speed->update(config.return_speed);
-                       ((MotionWindow*)thread->window)->rotate_magnitude->update(config.rotate_magnitude);
-                       ((MotionWindow*)thread->window)->rotate_return_speed->update(config.rotate_return_speed);
-                       ((MotionWindow*)thread->window)->rotation_range->update(config.rotation_range);
-                       ((MotionWindow*)thread->window)->rotation_center->update(config.rotation_center);
-
-
-                       ((MotionWindow*)thread->window)->track_single->update(config.tracking_object == MotionScan::TRACK_SINGLE);
-                       ((MotionWindow*)thread->window)->track_frame_number->update(config.track_frame);
-                       ((MotionWindow*)thread->window)->track_previous->update(config.tracking_object == MotionScan::TRACK_PREVIOUS);
-                       ((MotionWindow*)thread->window)->previous_same->update(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK);
-                       if(config.tracking_object != MotionScan::TRACK_SINGLE)
-                               ((MotionWindow*)thread->window)->track_frame_number->disable();
+                       thread->window->lock_window("MotionHVMain::update_gui");
+
+//                     char string[BCTEXTLEN];
+//                     sprintf(string, "%d", config.global_positions);
+//                     ((MotionHVWindow*)thread->window)->global_search_positions->set_text(string);
+//                     sprintf(string, "%d", config.rotate_positions);
+//                     ((MotionHVWindow*)thread->window)->rotation_search_positions->set_text(string);
+
+                       ((MotionHVWindow*)thread->window)->global_block_w->update(config.global_block_w);
+                       ((MotionHVWindow*)thread->window)->global_block_h->update(config.global_block_h);
+//                     ((MotionHVWindow*)thread->window)->rotation_block_w->update(config.rotation_block_w);
+//                     ((MotionHVWindow*)thread->window)->rotation_block_h->update(config.rotation_block_h);
+                       ((MotionHVWindow*)thread->window)->block_x->update(config.block_x);
+                       ((MotionHVWindow*)thread->window)->block_y->update(config.block_y);
+                       ((MotionHVWindow*)thread->window)->block_x_text->update((float)config.block_x);
+                       ((MotionHVWindow*)thread->window)->block_y_text->update((float)config.block_y);
+                       ((MotionHVWindow*)thread->window)->magnitude->update(config.magnitude);
+                       ((MotionHVWindow*)thread->window)->return_speed->update(config.return_speed);
+                       ((MotionHVWindow*)thread->window)->rotate_magnitude->update(config.rotate_magnitude);
+                       ((MotionHVWindow*)thread->window)->rotate_return_speed->update(config.rotate_return_speed);
+                       ((MotionHVWindow*)thread->window)->rotation_range->update(config.rotation_range);
+                       ((MotionHVWindow*)thread->window)->rotation_center->update(config.rotation_center);
+
+
+                       ((MotionHVWindow*)thread->window)->track_single->update(config.tracking_object == MotionHVScan::TRACK_SINGLE);
+                       ((MotionHVWindow*)thread->window)->track_frame_number->update(config.track_frame);
+                       ((MotionHVWindow*)thread->window)->track_previous->update(config.tracking_object == MotionHVScan::TRACK_PREVIOUS);
+                       ((MotionHVWindow*)thread->window)->previous_same->update(config.tracking_object == MotionHVScan::PREVIOUS_SAME_BLOCK);
+                       if(config.tracking_object != MotionHVScan::TRACK_SINGLE)
+                               ((MotionHVWindow*)thread->window)->track_frame_number->disable();
                        else
-                               ((MotionWindow*)thread->window)->track_frame_number->enable();
+                               ((MotionHVWindow*)thread->window)->track_frame_number->enable();
 
-                       ((MotionWindow*)thread->window)->action_type->set_text(
+                       ((MotionHVWindow*)thread->window)->action_type->set_text(
                                ActionType::to_text(config.action_type));
-                       ((MotionWindow*)thread->window)->tracking_type->set_text(
+                       ((MotionHVWindow*)thread->window)->tracking_type->set_text(
                                TrackingType::to_text(config.tracking_type));
-                       ((MotionWindow*)thread->window)->track_direction->set_text(
+                       ((MotionHVWindow*)thread->window)->track_direction->set_text(
                                TrackDirection::to_text(config.horizontal_only, config.vertical_only));
-                       ((MotionWindow*)thread->window)->master_layer->set_text(
+                       ((MotionHVWindow*)thread->window)->master_layer->set_text(
                                MasterLayer::to_text(config.bottom_is_master));
 
 
-                       ((MotionWindow*)thread->window)->update_mode();
+                       ((MotionHVWindow*)thread->window)->update_mode();
                        thread->window->unlock_window();
                }
        }
@@ -326,7 +326,7 @@ void MotionMain::update_gui()
 
 
 
-void MotionMain::save_data(KeyFrame *keyframe)
+void MotionHVMain::save_data(KeyFrame *keyframe)
 {
        FileXML output;
 
@@ -335,12 +335,12 @@ void MotionMain::save_data(KeyFrame *keyframe)
        output.tag.set_title("MOTION");
 
        output.tag.set_property("BLOCK_COUNT", config.block_count);
-       output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
-       output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
+//     output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
+//     output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
        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("ROTATION_BLOCK_W", config.rotation_block_w);
-       output.tag.set_property("ROTATION_BLOCK_H", config.rotation_block_h);
+//     output.tag.set_property("ROTATION_BLOCK_W", config.rotation_block_w);
+//     output.tag.set_property("ROTATION_BLOCK_H", config.rotation_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);
@@ -352,7 +352,7 @@ void MotionMain::save_data(KeyFrame *keyframe)
        output.tag.set_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
        output.tag.set_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
        output.tag.set_property("ACTION_TYPE", config.action_type);
-       output.tag.set_property("GLOBAL", config.global);
+//     output.tag.set_property("GLOBAL", config.global);
        output.tag.set_property("ROTATE", config.rotate);
        output.tag.set_property("TRACKING_TYPE", config.tracking_type);
        output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
@@ -364,11 +364,10 @@ void MotionMain::save_data(KeyFrame *keyframe)
        output.append_tag();
        output.tag.set_title("/MOTION");
        output.append_tag();
-       output.append_newline();
        output.terminate_string();
 }
 
-void MotionMain::read_data(KeyFrame *keyframe)
+void MotionHVMain::read_data(KeyFrame *keyframe)
 {
        FileXML input;
 
@@ -385,12 +384,12 @@ void MotionMain::read_data(KeyFrame *keyframe)
                        if(input.tag.title_is("MOTION"))
                        {
                                config.block_count = input.tag.get_property("BLOCK_COUNT", config.block_count);
-                               config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
-                               config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
+//                             config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
+//                             config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
                                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.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
-                               config.rotation_block_h = input.tag.get_property("ROTATION_BLOCK_H", config.rotation_block_h);
+//                             config.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
+//                             config.rotation_block_h = input.tag.get_property("ROTATION_BLOCK_H", config.rotation_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);
@@ -402,7 +401,7 @@ void MotionMain::read_data(KeyFrame *keyframe)
                                config.rotate_magnitude = input.tag.get_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
                                config.rotate_return_speed = input.tag.get_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
                                config.action_type = input.tag.get_property("ACTION_TYPE", config.action_type);
-                               config.global = input.tag.get_property("GLOBAL", config.global);
+//                             config.global = input.tag.get_property("GLOBAL", config.global);
                                config.rotate = input.tag.get_property("ROTATE", config.rotate);
                                config.tracking_type = input.tag.get_property("TRACKING_TYPE", config.tracking_type);
                                config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
@@ -425,7 +424,7 @@ void MotionMain::read_data(KeyFrame *keyframe)
 
 
 
-void MotionMain::allocate_temp(int w, int h, int color_model)
+void MotionHVMain::allocate_temp(int w, int h, int color_model)
 {
        if(temp_frame &&
                (temp_frame->get_w() != w ||
@@ -439,46 +438,54 @@ void MotionMain::allocate_temp(int w, int h, int color_model)
 }
 
 
-void MotionMain::process_global()
+void MotionHVMain::process_global()
 {
+       int w = current_global_ref->get_w();
+       int h = current_global_ref->get_h();
 
-       if(!engine) engine = new MotionScan(PluginClient::get_project_smp() + 1,
+
+       if(!engine) engine = new MotionHVScan(PluginClient::get_project_smp() + 1,
                PluginClient::get_project_smp() + 1);
 
 // Determine if frames changed
+// printf("MotionHVMain::process_global %d block_y=%f total_dy=%d\n",
+//  __LINE__, config.block_y * h / 100, total_dy);
        engine->scan_frame(current_global_ref,
                prev_global_ref,
-               config.global_range_w,
-               config.global_range_h,
-               config.global_block_w,
-               config.global_block_h,
-               config.block_x,
-               config.block_y,
+               config.global_range_w * w / 100,
+               config.global_range_h * h / 100,
+               config.global_block_w * w / 100,
+               config.global_block_h * h / 100,
+               config.block_x * w / 100,
+               config.block_y * h / 100,
                config.tracking_object,
                config.tracking_type,
                config.action_type,
                config.horizontal_only,
                config.vertical_only,
                get_source_position(),
-               config.global_positions,
                total_dx,
                total_dy,
                0,
-               0);
+               0,
+               1, // do_motion
+               config.rotate, // do_rotate
+               config.rotation_center,
+               config.rotation_range);
+
        current_dx = engine->dx_result;
        current_dy = engine->dy_result;
 
 // Add current motion vector to accumulation vector.
-       if(config.tracking_object != MotionScan::TRACK_SINGLE)
+       if(config.tracking_object != MotionHVScan::TRACK_SINGLE)
        {
 // Retract over time
                total_dx = (int64_t)total_dx * (100 - config.return_speed) / 100;
                total_dy = (int64_t)total_dy * (100 - config.return_speed) / 100;
                total_dx += engine->dx_result;
                total_dy += engine->dy_result;
-// printf("MotionMain::process_global total_dx=%d engine->dx_result=%d\n",
-// total_dx,
-// engine->dx_result);
+// printf("MotionHVMain::process_global %d total_dy=%d engine->dy_result=%d\n",
+//  __LINE__, total_dy, engine->dy_result);
        }
        else
 // Make accumulation vector current
@@ -490,45 +497,29 @@ void MotionMain::process_global()
 // Clamp accumulation vector
        if(config.magnitude < 100)
        {
-               int block_w = (int64_t)config.global_block_w *
-                               current_global_ref->get_w() / 100;
-               int block_h = (int64_t)config.global_block_h *
-                               current_global_ref->get_h() / 100;
-               int block_x_orig = (int64_t)(config.block_x *
-                       current_global_ref->get_w() /
-                       100);
+               //int block_w = (int64_t)config.global_block_w * w / 100;
+               //int block_h = (int64_t)config.global_block_h * h / 100;
+               int block_x_orig = (int64_t)(config.block_x * w / 100);
                int block_y_orig = (int64_t)(config.block_y *
-                       current_global_ref->get_h() /
-                       100);
+                       current_global_ref->get_h() / h / 100);
 
-               int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
-               int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
+               int max_block_x = (int64_t)(w - block_x_orig) *
+                       OVERSAMPLE * config.magnitude / 100;
+               int max_block_y = (int64_t)(h - block_y_orig) *
+                       OVERSAMPLE * config.magnitude / 100;
                int min_block_x = (int64_t)-block_x_orig *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
+                       OVERSAMPLE * config.magnitude / 100;
                int min_block_y = (int64_t)-block_y_orig *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
+                       OVERSAMPLE * config.magnitude / 100;
 
                CLAMP(total_dx, min_block_x, max_block_x);
                CLAMP(total_dy, min_block_y, max_block_y);
        }
 
-#ifdef DEBUG
-printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
-(float)total_dx / OVERSAMPLE,
-(float)total_dy / OVERSAMPLE);
-#endif
+// printf("MotionHVMain::process_global %d total_dx=%d total_dy=%d\n",
+//  __LINE__, total_dx, total_dy);
 
-       if(config.tracking_object != MotionScan::TRACK_SINGLE && !config.rotate)
+       if(config.tracking_object != MotionHVScan::TRACK_SINGLE && !config.rotate)
        {
 // Transfer current reference frame to previous reference frame and update
 // counter.  Must wait for rotate to compare.
@@ -537,31 +528,30 @@ printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
        }
 
 // Decide what to do with target based on requested operation
-       int interpolation;
-       float dx;
-       float dy;
+       int interpolation = NEAREST_NEIGHBOR;
+       float dx = 0.;
+       float dy = 0.;
        switch(config.action_type)
        {
-               case MotionScan::NOTHING:
+               case MotionHVScan::NOTHING:
                        global_target_dst->copy_from(global_target_src);
                        break;
-               case MotionScan::TRACK_PIXEL:
+               case MotionHVScan::TRACK_PIXEL:
                        interpolation = NEAREST_NEIGHBOR;
                        dx = (int)(total_dx / OVERSAMPLE);
                        dy = (int)(total_dy / OVERSAMPLE);
                        break;
-               case MotionScan::STABILIZE_PIXEL:
+               case MotionHVScan::STABILIZE_PIXEL:
                        interpolation = NEAREST_NEIGHBOR;
                        dx = -(int)(total_dx / OVERSAMPLE);
                        dy = -(int)(total_dy / OVERSAMPLE);
                        break;
-                       break;
-               case MotionScan::TRACK:
+               case MotionHVScan::TRACK:
                        interpolation = CUBIC_LINEAR;
                        dx = (float)total_dx / OVERSAMPLE;
                        dy = (float)total_dy / OVERSAMPLE;
                        break;
-               case MotionScan::STABILIZE:
+               case MotionHVScan::STABILIZE:
                        interpolation = CUBIC_LINEAR;
                        dx = -(float)total_dx / OVERSAMPLE;
                        dy = -(float)total_dy / OVERSAMPLE;
@@ -569,7 +559,7 @@ printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
        }
 
 
-       if(config.action_type != MotionScan::NOTHING)
+       if(config.action_type != MotionHVScan::NOTHING)
        {
                if(!overlayer)
                        overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
@@ -592,20 +582,22 @@ printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
 
 
 
-void MotionMain::process_rotation()
+void MotionHVMain::process_rotation()
 {
        int block_x;
        int block_y;
 
+// Always require global
 // Convert the previous global reference into the previous rotation reference.
 // Convert global target destination into rotation target source.
-       if(config.global)
+//     if(config.global)
+       if(1)
        {
                if(!overlayer)
                        overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
                float dx;
                float dy;
-               if(config.tracking_object == MotionScan::TRACK_SINGLE)
+               if(config.tracking_object == MotionHVScan::TRACK_SINGLE)
                {
                        dx = (float)total_dx / OVERSAMPLE;
                        dy = (float)total_dy / OVERSAMPLE;
@@ -644,7 +636,7 @@ void MotionMain::process_rotation()
 // Use the global target output as the rotation target input
                rotate_target_src->copy_from(global_target_dst);
 // Transfer current reference frame to previous reference frame for global.
-               if(config.tracking_object != MotionScan::TRACK_SINGLE)
+               if(config.tracking_object != MotionHVScan::TRACK_SINGLE)
                {
                        prev_global_ref->copy_from(current_global_ref);
                        previous_frame_number = get_source_position();
@@ -664,20 +656,20 @@ void MotionMain::process_rotation()
 
 
 // Get rotation
-       if(!motion_rotate)
-               motion_rotate = new RotateScan(this,
-                       get_project_smp() + 1,
-                       get_project_smp() + 1);
-
-       current_angle = motion_rotate->scan_frame(prev_rotate_ref,
-               current_rotate_ref,
-               block_x,
-               block_y);
-
-
+//     if(!motion_rotate)
+//             motion_rotate = new RotateScan(this,
+//                     get_project_smp() + 1,
+//                     get_project_smp() + 1);
+//
+//     current_angle = motion_rotate->scan_frame(prev_rotate_ref,
+//             current_rotate_ref,
+//             block_x,
+//             block_y);
+
+       current_angle = engine->dr_result;
 
 // Add current rotation to accumulation
-       if(config.tracking_object != MotionScan::TRACK_SINGLE)
+       if(config.tracking_object != MotionHVScan::TRACK_SINGLE)
        {
 // Retract over time
                total_angle = total_angle * (100 - config.rotate_return_speed) / 100;
@@ -690,13 +682,13 @@ void MotionMain::process_rotation()
                        CLAMP(total_angle, -config.rotate_magnitude, config.rotate_magnitude);
                }
 
-               if(!config.global)
-               {
+//             if(!config.global)
+//             {
 // Transfer current reference frame to previous reference frame and update
 // counter.
-                       prev_rotate_ref->copy_from(current_rotate_ref);
-                       previous_frame_number = get_source_position();
-               }
+//                     prev_rotate_ref->copy_from(current_rotate_ref);
+//                     previous_frame_number = get_source_position();
+//             }
        }
        else
        {
@@ -704,30 +696,30 @@ void MotionMain::process_rotation()
        }
 
 #ifdef DEBUG
-printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
+printf("MotionHVMain::process_rotation total_angle=%f\n", total_angle);
 #endif
 
 
 // Calculate rotation parameters based on requested operation
-       float angle;
+       float angle = 0.;
        switch(config.action_type)
        {
-               case MotionScan::NOTHING:
+               case MotionHVScan::NOTHING:
                        rotate_target_dst->copy_from(rotate_target_src);
                        break;
-               case MotionScan::TRACK:
-               case MotionScan::TRACK_PIXEL:
+               case MotionHVScan::TRACK:
+               case MotionHVScan::TRACK_PIXEL:
                        angle = total_angle;
                        break;
-               case MotionScan::STABILIZE:
-               case MotionScan::STABILIZE_PIXEL:
+               case MotionHVScan::STABILIZE:
+               case MotionHVScan::STABILIZE_PIXEL:
                        angle = -total_angle;
                        break;
        }
 
 
 
-       if(config.action_type != MotionScan::NOTHING)
+       if(config.action_type != MotionHVScan::NOTHING)
        {
                if(!rotate_engine)
                        rotate_engine = new AffineEngine(PluginClient::get_project_smp() + 1,
@@ -738,17 +730,18 @@ printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
 // Determine pivot based on a number of factors.
                switch(config.action_type)
                {
-                       case MotionScan::TRACK:
-                       case MotionScan::TRACK_PIXEL:
+                       case MotionHVScan::TRACK:
+                       case MotionHVScan::TRACK_PIXEL:
 // Use destination of global tracking.
 //                             rotate_engine->set_pivot(block_x, block_y);
                                rotate_engine->set_in_pivot(block_x, block_y);
                                rotate_engine->set_out_pivot(block_x, block_y);
                                break;
 
-                       case MotionScan::STABILIZE:
-                       case MotionScan::STABILIZE_PIXEL:
-                               if(config.global)
+                       case MotionHVScan::STABILIZE:
+                       case MotionHVScan::STABILIZE_PIXEL:
+//                             if(config.global)
+                               if(1)
                                {
 // Use origin of global stabilize operation
 //                                     rotate_engine->set_pivot((int)(rotate_target_dst->get_w() *
@@ -782,6 +775,7 @@ printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
                }
 
 
+printf("MotionHVMain::process_rotation angle=%f\n", angle);
                rotate_engine->rotate(rotate_target_dst, rotate_target_src, angle);
 // overlayer->overlay(rotate_target_dst,
 //     prev_rotate_ref,
@@ -824,7 +818,7 @@ printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
 
 
 
-int MotionMain::process_buffer(VFrame **frame,
+int MotionHVMain::process_buffer(VFrame **frame,
        int64_t start_position,
        double frame_rate)
 {
@@ -835,7 +829,7 @@ int MotionMain::process_buffer(VFrame **frame,
 
 
 #ifdef DEBUG
-printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_position);
+printf("MotionHVMain::process_buffer %d start_position=%lld\n", __LINE__, start_position);
 #endif
 
 
@@ -859,7 +853,7 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
        int skip_current = 0;
 
 
-       if(config.tracking_object == MotionScan::TRACK_SINGLE)
+       if(config.tracking_object == MotionHVScan::TRACK_SINGLE)
        {
                actual_previous_number = config.track_frame;
                if(get_direction() == PLAY_REVERSE)
@@ -903,7 +897,7 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
        }
 
 
-       if(!config.global && !config.rotate) skip_current = 1;
+//     if(!config.global && !config.rotate) skip_current = 1;
 
 
 
@@ -939,7 +933,8 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
 
 
 // Get the global pointers.  Here we walk through the sequence of events.
-       if(config.global)
+//     if(config.global)
+       if(1)
        {
 // Assume global only.  Global reads previous frame and compares
 // with current frame to get the current translation.
@@ -964,17 +959,20 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
                        read_frame(prev_global_ref,
                                reference_layer,
                                previous_frame_number,
-                               frame_rate);
+                               frame_rate,
+                               0);
                }
 
                read_frame(current_global_ref,
                        reference_layer,
                        start_position,
-                       frame_rate);
+                       frame_rate,
+                       0);
                read_frame(global_target_src,
                        target_layer,
                        start_position,
-                       frame_rate);
+                       frame_rate,
+                       0);
 
 
 
@@ -1028,16 +1026,19 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
                        read_frame(prev_rotate_ref,
                                reference_layer,
                                previous_frame_number,
-                               frame_rate);
+                               frame_rate,
+                               0);
                }
                read_frame(current_rotate_ref,
                        reference_layer,
                        start_position,
-                       frame_rate);
+                       frame_rate,
+                       0);
                read_frame(rotate_target_src,
                        target_layer,
                        start_position,
-                       frame_rate);
+                       frame_rate,
+                       0);
        }
 
 
@@ -1046,13 +1047,14 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
 
 
 
-
+//PRINT_TRACE
+//printf("skip_current=%d config.global=%d\n", skip_current, config.global);
 
 
        if(!skip_current)
        {
 // Get position change from previous frame to current frame
-               if(config.global) process_global();
+               /* if(config.global) */ process_global();
 // Get rotation change from previous frame to current frame
                if(config.rotate) process_rotation();
 //frame[target_layer]->copy_from(prev_rotate_ref);
@@ -1082,7 +1084,8 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
                read_frame(frame[target_layer],
                        target_layer,
                        start_position,
-                       frame_rate);
+                       frame_rate,
+                       0);
        }
 
        if(config.draw_vectors)
@@ -1091,14 +1094,14 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
        }
 
 #ifdef DEBUG
-printf("MotionMain::process_buffer %d\n", __LINE__);
+printf("MotionHVMain::process_buffer %d\n", __LINE__);
 #endif
        return 0;
 }
 
 
 
-void MotionMain::draw_vectors(VFrame *frame)
+void MotionHVMain::draw_vectors(VFrame *frame)
 {
        int w = frame->get_w();
        int h = frame->get_h();
@@ -1113,16 +1116,16 @@ void MotionMain::draw_vectors(VFrame *frame)
        int search_w, search_h;
        int search_x1, search_y1;
        int search_x2, search_y2;
-       int search_x3, search_y3;
-       int search_x4, search_y4;
 
 
-       if(config.global)
+// always processing global
+//     if(config.global)
+       if(1)
        {
 // Get vector
 // Start of vector is center of previous block.
 // End of vector is total accumulation.
-               if(config.tracking_object == MotionScan::TRACK_SINGLE)
+               if(config.tracking_object == MotionHVScan::TRACK_SINGLE)
                {
                        global_x1 = (int64_t)(config.block_x *
                                w /
@@ -1132,12 +1135,12 @@ void MotionMain::draw_vectors(VFrame *frame)
                                100);
                        global_x2 = global_x1 + total_dx / OVERSAMPLE;
                        global_y2 = global_y1 + total_dy / OVERSAMPLE;
-//printf("MotionMain::draw_vectors %d %d %d %d %d %d\n", total_dx, total_dy, global_x1, global_y1, global_x2, global_y2);
+//printf("MotionHVMain::draw_vectors %d %d %d %d %d %d\n", total_dx, total_dy, global_x1, global_y1, global_x2, global_y2);
                }
                else
 // Start of vector is center of previous block.
 // End of vector is current change.
-               if(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK)
+               if(config.tracking_object == MotionHVScan::PREVIOUS_SAME_BLOCK)
                {
                        global_x1 = (int64_t)(config.block_x *
                                w /
@@ -1187,7 +1190,7 @@ void MotionMain::draw_vectors(VFrame *frame)
                search_x2 = block_x2 + search_w / 2;
                search_y2 = block_y2 + search_h / 2;
 
-// printf("MotionMain::draw_vectors %d %d %d %d %d %d %d %d %d %d %d %d\n",
+// printf("MotionHVMain::draw_vectors %d %d %d %d %d %d %d %d %d %d %d %d\n",
 // global_x1,
 // global_y1,
 // block_w,
@@ -1201,7 +1204,7 @@ void MotionMain::draw_vectors(VFrame *frame)
 // search_x2,
 // search_y2);
 
-               MotionScan::clamp_scan(w,
+               MotionHVScan::clamp_scan(w,
                        h,
                        &block_x1,
                        &block_y1,
@@ -1242,8 +1245,8 @@ void MotionMain::draw_vectors(VFrame *frame)
                block_y = (int64_t)(config.block_y * h / 100);
        }
 
-       block_w = config.rotation_block_w * w / 100;
-       block_h = config.rotation_block_h * h / 100;
+       block_w = config.global_block_w * w / 100;
+       block_h = config.global_block_h * h / 100;
        if(config.rotate)
        {
                float angle = total_angle * 2 * M_PI / 360;
@@ -1278,7 +1281,7 @@ void MotionMain::draw_vectors(VFrame *frame)
 
 
 
-void MotionMain::draw_pixel(VFrame *frame, int x, int y)
+void MotionHVMain::draw_pixel(VFrame *frame, int x, int y)
 {
        if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
 
@@ -1337,11 +1340,11 @@ void MotionMain::draw_pixel(VFrame *frame, int x, int y)
 }
 
 
-void MotionMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
+void MotionHVMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
 {
        int w = labs(x2 - x1);
        int h = labs(y2 - y1);
-//printf("MotionMain::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
+//printf("MotionHVMain::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
 
        if(!w && !h)
        {
@@ -1388,11 +1391,11 @@ void MotionMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
                        draw_pixel(frame, x, i);
                }
        }
-//printf("MotionMain::draw_line 2\n");
+//printf("MotionHVMain::draw_line 2\n");
 }
 
 #define ARROW_SIZE 10
-void MotionMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
+void MotionHVMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
 {
        double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
        double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
@@ -1434,442 +1437,3 @@ void MotionMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
 
 
 
-
-
-
-
-
-
-
-
-
-RotateScanPackage::RotateScanPackage()
-{
-}
-
-
-RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
- : LoadClient(server)
-{
-       this->server = server;
-       this->plugin = plugin;
-       rotater = 0;
-       temp = 0;
-}
-
-RotateScanUnit::~RotateScanUnit()
-{
-       delete rotater;
-       delete temp;
-}
-
-void RotateScanUnit::process_package(LoadPackage *package)
-{
-       if(server->skip) return;
-       RotateScanPackage *pkg = (RotateScanPackage*)package;
-
-       if((pkg->difference = server->get_cache(pkg->angle)) < 0)
-       {
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-               int color_model = server->previous_frame->get_color_model();
-               int pixel_size = BC_CModels::calculate_pixelsize(color_model);
-               int row_bytes = server->previous_frame->get_bytes_per_line();
-
-               if(!rotater)
-                       rotater = new AffineEngine(1, 1);
-               if(!temp) temp = new VFrame(0,
-                       -1,
-                       server->previous_frame->get_w(),
-                       server->previous_frame->get_h(),
-                       color_model,
-                       -1);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-
-
-// Rotate original block size
-//             rotater->set_viewport(server->block_x1,
-//                     server->block_y1,
-//                     server->block_x2 - server->block_x1,
-//                     server->block_y2 - server->block_y1);
-               rotater->set_in_viewport(server->block_x1,
-                       server->block_y1,
-                       server->block_x2 - server->block_x1,
-                       server->block_y2 - server->block_y1);
-               rotater->set_out_viewport(server->block_x1,
-                       server->block_y1,
-                       server->block_x2 - server->block_x1,
-                       server->block_y2 - server->block_y1);
-//             rotater->set_pivot(server->block_x, server->block_y);
-               rotater->set_in_pivot(server->block_x, server->block_y);
-               rotater->set_out_pivot(server->block_x, server->block_y);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-               rotater->rotate(temp,
-                       server->previous_frame,
-                       pkg->angle);
-
-// Scan reduced block size
-//plugin->output_frame->copy_from(server->current_frame);
-//plugin->output_frame->copy_from(temp);
-// printf("RotateScanUnit::process_package %d %d %d %d %d\n",
-// __LINE__,
-// server->scan_x,
-// server->scan_y,
-// server->scan_w,
-// server->scan_h);
-// Clamp coordinates
-               int x1 = server->scan_x;
-               int y1 = server->scan_y;
-               int x2 = x1 + server->scan_w;
-               int y2 = y1 + server->scan_h;
-               x2 = MIN(temp->get_w(), x2);
-               y2 = MIN(temp->get_h(), y2);
-               x2 = MIN(server->current_frame->get_w(), x2);
-               y2 = MIN(server->current_frame->get_h(), y2);
-               x1 = MAX(0, x1);
-               y1 = MAX(0, y1);
-
-               if(x2 > x1 && y2 > y1)
-               {
-                       pkg->difference = MotionScan::abs_diff(
-                               temp->get_rows()[y1] + x1 * pixel_size,
-                               server->current_frame->get_rows()[y1] + x1 * pixel_size,
-                               row_bytes,
-                               x2 - x1,
-                               y2 - y1,
-                               color_model);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-                       server->put_cache(pkg->angle, pkg->difference);
-               }
-
-// printf("RotateScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%lld\n",
-// server->block_x1,
-// server->block_y1,
-// server->block_x2 - server->block_x1,
-// server->block_y2 - server->block_y1,
-// server->block_x,
-// server->block_y,
-// pkg->angle,
-// server->scan_w,
-// server->scan_h,
-// pkg->difference);
-       }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-RotateScan::RotateScan(MotionMain *plugin,
-       int total_clients,
-       int total_packages)
- : LoadServer(
-//1, 1
-total_clients, total_packages
-)
-{
-       this->plugin = plugin;
-       cache_lock = new Mutex("RotateScan::cache_lock");
-}
-
-
-RotateScan::~RotateScan()
-{
-       delete cache_lock;
-}
-
-void RotateScan::init_packages()
-{
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
-               pkg->angle = i *
-                       (scan_angle2 - scan_angle1) /
-                       (total_steps - 1) +
-                       scan_angle1;
-       }
-}
-
-LoadClient* RotateScan::new_client()
-{
-       return new RotateScanUnit(this, plugin);
-}
-
-LoadPackage* RotateScan::new_package()
-{
-       return new RotateScanPackage;
-}
-
-
-float RotateScan::scan_frame(VFrame *previous_frame,
-       VFrame *current_frame,
-       int block_x,
-       int block_y)
-{
-       skip = 0;
-       this->block_x = block_x;
-       this->block_y = block_y;
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
-       switch(plugin->config.tracking_type)
-       {
-               case MotionScan::NO_CALCULATE:
-                       result = plugin->config.rotation_center;
-                       skip = 1;
-                       break;
-
-               case MotionScan::LOAD:
-               {
-                       char string[BCTEXTLEN];
-                       sprintf(string, "%s%06d", ROTATION_FILE, plugin->get_source_position());
-                       FILE *input = fopen(string, "r");
-                       if(input)
-                       {
-                               fscanf(input, "%f", &result);
-                               fclose(input);
-                               skip = 1;
-                       }
-                       else
-                       {
-                               perror("RotateScan::scan_frame LOAD");
-                       }
-                       break;
-               }
-       }
-
-
-
-
-
-
-
-
-       this->previous_frame = previous_frame;
-       this->current_frame = current_frame;
-       int w = current_frame->get_w();
-       int h = current_frame->get_h();
-       int block_w = w * plugin->config.rotation_block_w / 100;
-       int block_h = h * plugin->config.rotation_block_h / 100;
-
-       if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
-       if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
-       if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
-       if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
-
-       block_x1 = this->block_x - block_w / 2;
-       block_x2 = this->block_x + block_w / 2;
-       block_y1 = this->block_y - block_h / 2;
-       block_y2 = this->block_y + block_h / 2;
-
-
-// Calculate the maximum area available to scan after rotation.
-// Must be calculated from the starting range because of cache.
-// Get coords of rectangle after rotation.
-       double center_x = this->block_x;
-       double center_y = this->block_y;
-       double max_angle = plugin->config.rotation_range;
-       double base_angle1 = atan((float)block_h / block_w);
-       double base_angle2 = atan((float)block_w / block_h);
-       double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
-       double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
-       double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
-       double x1 = center_x - cos(target_angle1) * radius;
-       double y1 = center_y - sin(target_angle1) * radius;
-       double x2 = center_x + sin(target_angle2) * radius;
-       double y2 = center_y - cos(target_angle2) * radius;
-       double x3 = center_x - sin(target_angle2) * radius;
-       double y3 = center_y + cos(target_angle2) * radius;
-
-// Track top edge to find greatest area.
-       double max_area1 = 0;
-       double max_x1 = 0;
-       double max_y1 = 0;
-       for(double x = x1; x < x2; x++)
-       {
-               double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
-               if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
-               {
-                       double area = fabs(x - center_x) * fabs(y - center_y);
-                       if(area > max_area1)
-                       {
-                               max_area1 = area;
-                               max_x1 = x;
-                               max_y1 = y;
-                       }
-               }
-       }
-
-// Track left edge to find greatest area.
-       double max_area2 = 0;
-       double max_x2 = 0;
-       double max_y2 = 0;
-       for(double y = y1; y < y3; y++)
-       {
-               double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
-               if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
-               {
-                       double area = fabs(x - center_x) * fabs(y - center_y);
-                       if(area > max_area2)
-                       {
-                               max_area2 = area;
-                               max_x2 = x;
-                               max_y2 = y;
-                       }
-               }
-       }
-
-       double max_x, max_y;
-       max_x = max_x2;
-       max_y = max_y1;
-
-// Get reduced scan coords
-       scan_w = (int)(fabs(max_x - center_x) * 2);
-       scan_h = (int)(fabs(max_y - center_y) * 2);
-       scan_x = (int)(center_x - scan_w / 2);
-       scan_y = (int)(center_y - scan_h / 2);
-// printf("RotateScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n",
-// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
-// printf("    angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
-
-// Determine min angle from size of block
-       double angle1 = atan((double)block_h / block_w);
-       double angle2 = atan((double)(block_h - 1) / (block_w + 1));
-       double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
-       min_angle = MAX(min_angle, MIN_ANGLE);
-
-//printf("RotateScan::scan_frame %d min_angle=%f\n", __LINE__, min_angle * 360 / 2 / M_PI);
-
-       cache.remove_all_objects();
-
-
-       if(!skip)
-       {
-               if(previous_frame->data_matches(current_frame))
-               {
-//printf("RotateScan::scan_frame: frames match.  Skipping.\n");
-                       result = plugin->config.rotation_center;
-                       skip = 1;
-               }
-       }
-
-       if(!skip)
-       {
-// Initial search range
-               float angle_range = max_angle;
-               result = plugin->config.rotation_center;
-               total_steps = plugin->config.rotate_positions;
-
-
-               while(angle_range >= min_angle * total_steps)
-               {
-                       scan_angle1 = result - angle_range;
-                       scan_angle2 = result + angle_range;
-
-
-                       set_package_count(total_steps);
-//set_package_count(1);
-                       process_packages();
-
-                       int64_t min_difference = -1;
-                       for(int i = 0; i < get_total_packages(); i++)
-                       {
-                               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
-                               if(pkg->difference < min_difference || min_difference == -1)
-                               {
-                                       min_difference = pkg->difference;
-                                       result = pkg->angle;
-                               }
-//break;
-                       }
-
-                       angle_range /= 2;
-
-//break;
-               }
-       }
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
-
-       if(!skip && plugin->config.tracking_type == MotionScan::SAVE)
-       {
-               char string[BCTEXTLEN];
-               sprintf(string,
-                       "%s%06d",
-                       ROTATION_FILE,
-                       plugin->get_source_position());
-               FILE *output = fopen(string, "w");
-               if(output)
-               {
-                       fprintf(output, "%f\n", result);
-                       fclose(output);
-               }
-               else
-               {
-                       perror("RotateScan::scan_frame SAVE");
-               }
-       }
-
-//printf("RotateScan::scan_frame %d angle=%f\n", __LINE__, result);
-
-
-
-       return result;
-}
-
-int64_t RotateScan::get_cache(float angle)
-{
-       int64_t result = -1;
-       cache_lock->lock("RotateScan::get_cache");
-       for(int i = 0; i < cache.total; i++)
-       {
-               RotateScanCache *ptr = cache.values[i];
-               if(fabs(ptr->angle - angle) <= MIN_ANGLE)
-               {
-                       result = ptr->difference;
-                       break;
-               }
-       }
-       cache_lock->unlock();
-       return result;
-}
-
-void RotateScan::put_cache(float angle, int64_t difference)
-{
-       RotateScanCache *ptr = new RotateScanCache(angle, difference);
-       cache_lock->lock("RotateScan::put_cache");
-       cache.append(ptr);
-       cache_lock->unlock();
-}
-
-
-
-
-
-
-
-
-
-RotateScanCache::RotateScanCache(float angle, int64_t difference)
-{
-       this->angle = angle;
-       this->difference = difference;
-}
-
-
-
similarity index 69%
rename from cinelerra-5.1/plugins/motion.new/motion.h
rename to cinelerra-5.1/plugins/motion-hv/motion-hv.h
index 9ace96136f25655fe49438489cb158aab44d586a..f375fb43d394772797874ac219397de142f073c4 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 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
 #include "filexml.inc"
 #include "keyframe.inc"
 #include "loadbalance.h"
-#include "motionscan.inc"
-#include "motionwindow.inc"
+#include "motionscan-hv.inc"
+#include "motionwindow-hv.inc"
 #include "overlayframe.inc"
 #include "pluginvclient.h"
-#include "rotateframe.inc"
 #include "vframe.inc"
 
-class MotionMain;
-class MotionWindow;
-class RotateScan;
+class MotionHVMain;
+class MotionHVWindow;
 
 
 
@@ -64,17 +62,16 @@ class RotateScan;
 // Precision of rotation
 #define MIN_ANGLE 0.0001
 
-#define ROTATION_FILE "/tmp/rotate"
 
-class MotionConfig
+class MotionHVConfig
 {
 public:
-       MotionConfig();
+       MotionHVConfig();
 
-       int equivalent(MotionConfig &that);
-       void copy_from(MotionConfig &that);
-       void interpolate(MotionConfig &prev,
-               MotionConfig &next,
+       int equivalent(MotionHVConfig &that);
+       void copy_from(MotionHVConfig &that);
+       void interpolate(MotionHVConfig &prev,
+               MotionHVConfig &next,
                int64_t prev_frame,
                int64_t next_frame,
                int64_t current_frame);
@@ -95,11 +92,11 @@ public:
 // Percent of image size
        int global_block_w;
        int global_block_h;
-       int rotation_block_w;
-       int rotation_block_h;
+//     int rotation_block_w;
+//     int rotation_block_h;
 // Number of search positions in each refinement of the log search
-       int global_positions;
-       int rotate_positions;
+//     int global_positions;
+//     int rotate_positions;
 // Block position in percentage 0 - 100
        double block_x;
        double block_y;
@@ -146,11 +143,11 @@ public:
 
 
 
-class MotionMain : public PluginVClient
+class MotionHVMain : public PluginVClient
 {
 public:
-       MotionMain(PluginServer *server);
-       ~MotionMain();
+       MotionHVMain(PluginServer *server);
+       ~MotionHVMain();
 
        int process_buffer(VFrame **frame,
                int64_t start_position,
@@ -167,7 +164,7 @@ public:
        void calculate_pointers(VFrame **frame, VFrame **src, VFrame **dst);
        void allocate_temp(int w, int h, int color_model);
 
-       PLUGIN_CLASS_MEMBERS2(MotionConfig)
+       PLUGIN_CLASS_MEMBERS2(MotionHVConfig)
 
 
        static void draw_pixel(VFrame *frame, int x, int y);
@@ -179,8 +176,8 @@ public:
 // The frame compared with the previous frame to get the motion.
 // It is moved to compensate for motion and copied to the previous_frame.
        VFrame *temp_frame;
-       MotionScan *engine;
-       RotateScan *motion_rotate;
+       MotionHVScan *engine;
+//     RotateScan *motion_rotate;
        OverlayFrame *overlayer;
        AffineEngine *rotate_engine;
 
@@ -246,110 +243,6 @@ public:
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-class RotateScanPackage : public LoadPackage
-{
-public:
-       RotateScanPackage();
-       float angle;
-       int64_t difference;
-};
-
-class RotateScanCache
-{
-public:
-       RotateScanCache(float angle, int64_t difference);
-       float angle;
-       int64_t difference;
-};
-
-class RotateScanUnit : public LoadClient
-{
-public:
-       RotateScanUnit(RotateScan *server, MotionMain *plugin);
-       ~RotateScanUnit();
-
-       void process_package(LoadPackage *package);
-
-       RotateScan *server;
-       MotionMain *plugin;
-       AffineEngine *rotater;
-       VFrame *temp;
-};
-
-class RotateScan : public LoadServer
-{
-public:
-       RotateScan(MotionMain *plugin,
-               int total_clients,
-               int total_packages);
-       ~RotateScan();
-
-       friend class RotateScanUnit;
-
-       void init_packages();
-       LoadClient* new_client();
-       LoadPackage* new_package();
-
-// Invoke the motion engine for a search
-// Frame before rotation
-       float scan_frame(VFrame *previous_frame,
-// Frame after rotation
-               VFrame *current_frame,
-// Pivot
-               int block_x,
-               int block_y);
-       int64_t get_cache(float angle);
-       void put_cache(float angle, int64_t difference);
-
-
-// Angle result
-       float result;
-
-private:
-       VFrame *previous_frame;
-// Frame after motion
-       VFrame *current_frame;
-
-       MotionMain *plugin;
-       int skip;
-
-// Pivot
-       int block_x;
-       int block_y;
-// Block to rotate
-       int block_x1;
-       int block_x2;
-       int block_y1;
-       int block_y2;
-// Area to compare
-       int scan_x;
-       int scan_y;
-       int scan_w;
-       int scan_h;
-// Range of angles to compare
-       float scan_angle1, scan_angle2;
-       int total_steps;
-
-       ArrayList<RotateScanCache*> cache;
-       Mutex *cache_lock;
-};
-
-
-
-
 #endif
 
 
similarity index 90%
rename from cinelerra-5.1/plugins/motion.new/motion.inc
rename to cinelerra-5.1/plugins/motion-hv/motion-hv.inc
index cf71a2a44f78873aafdfab11f35b693fa34785d8..b8b8795d8f19a429e9fcd28158c393b800e86d0c 100644 (file)
  *
  */
 
-#ifndef MOTION_INC
-#define MOTION_INC
+#ifndef MOTIONHV_INC
+#define MOTIONHV_INC
 
 
-class MotionConfig;
-class MotionMain;
+class MotionHVConfig;
+class MotionHVMain;
 
 
 #endif
diff --git a/cinelerra-5.1/plugins/motion-hv/motionscan-hv.C b/cinelerra-5.1/plugins/motion-hv/motionscan-hv.C
new file mode 100644 (file)
index 0000000..db8617e
--- /dev/null
@@ -0,0 +1,1936 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2016 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 "affine.h"
+#include "bcsignals.h"
+#include "clip.h"
+#include "motionscan-hv.h"
+#include "mutex.h"
+#include "vframe.h"
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+// The module which does the actual scanning
+
+// starting level of detail
+#define STARTING_DOWNSAMPLE 16
+// minimum size in each level of detail
+#define MIN_DOWNSAMPLED_SIZE 16
+// minimum scan range
+#define MIN_DOWNSAMPLED_SCAN 4
+// scan range for subpixel mode
+#define SUBPIXEL_RANGE 4
+
+MotionHVScanPackage::MotionHVScanPackage()
+ : LoadPackage()
+{
+       valid = 1;
+}
+
+
+
+
+
+
+MotionHVScanUnit::MotionHVScanUnit(MotionHVScan *server)
+ : LoadClient(server)
+{
+       this->server = server;
+}
+
+MotionHVScanUnit::~MotionHVScanUnit()
+{
+}
+
+
+void MotionHVScanUnit::single_pixel(MotionHVScanPackage *pkg)
+{
+       //int w = server->current_frame->get_w();
+       //int h = server->current_frame->get_h();
+       int color_model = server->current_frame->get_color_model();
+       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+       int row_bytes = server->current_frame->get_bytes_per_line();
+
+// printf("MotionHVScanUnit::process_package %d search_x=%d search_y=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n",
+// __LINE__,
+// pkg->search_x,
+// pkg->search_y,
+// pkg->scan_x1,
+// pkg->scan_y1,
+// pkg->scan_x2,
+// pkg->scan_y2,
+// server->x_steps,
+// server->y_steps);
+
+// Pointers to first pixel in each block
+       unsigned char *prev_ptr = server->previous_frame->get_rows()[
+               pkg->search_y] +
+               pkg->search_x * pixel_size;
+       unsigned char *current_ptr = 0;
+
+       if(server->do_rotate)
+       {
+               current_ptr = server->rotated_current[pkg->angle_step]->get_rows()[
+                       pkg->block_y1] +
+                       pkg->block_x1 * pixel_size;
+       }
+       else
+       {
+               current_ptr = server->current_frame->get_rows()[
+                       pkg->block_y1] +
+                       pkg->block_x1 * pixel_size;
+       }
+
+// Scan block
+       pkg->difference1 = MotionHVScan::abs_diff(prev_ptr,
+               current_ptr,
+               row_bytes,
+               pkg->block_x2 - pkg->block_x1,
+               pkg->block_y2 - pkg->block_y1,
+               color_model);
+
+// printf("MotionHVScanUnit::process_package %d angle_step=%d diff=%d\n",
+// __LINE__,
+// pkg->angle_step,
+// pkg->difference1);
+// printf("MotionHVScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n",
+// __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
+}
+
+void MotionHVScanUnit::subpixel(MotionHVScanPackage *pkg)
+{
+//PRINT_TRACE
+       //int w = server->current_frame->get_w();
+       //int h = server->current_frame->get_h();
+       int color_model = server->current_frame->get_color_model();
+       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+       int row_bytes = server->current_frame->get_bytes_per_line();
+       unsigned char *prev_ptr = server->previous_frame->get_rows()[
+               pkg->search_y] +
+               pkg->search_x * pixel_size;
+// neglect rotation
+       unsigned char *current_ptr = server->current_frame->get_rows()[
+               pkg->block_y1] +
+               pkg->block_x1 * pixel_size;
+
+// With subpixel, there are two ways to compare each position, one by shifting
+// the previous frame and two by shifting the current frame.
+       pkg->difference1 = MotionHVScan::abs_diff_sub(prev_ptr,
+               current_ptr,
+               row_bytes,
+               pkg->block_x2 - pkg->block_x1,
+               pkg->block_y2 - pkg->block_y1,
+               color_model,
+               pkg->sub_x,
+               pkg->sub_y);
+       pkg->difference2 = MotionHVScan::abs_diff_sub(current_ptr,
+               prev_ptr,
+               row_bytes,
+               pkg->block_x2 - pkg->block_x1,
+               pkg->block_y2 - pkg->block_y1,
+               color_model,
+               pkg->sub_x,
+               pkg->sub_y);
+// printf("MotionHVScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
+// pkg->sub_x,
+// pkg->sub_y,
+// pkg->search_x,
+// pkg->search_y,
+// pkg->difference1,
+// pkg->difference2);
+}
+
+void MotionHVScanUnit::process_package(LoadPackage *package)
+{
+       MotionHVScanPackage *pkg = (MotionHVScanPackage*)package;
+
+
+// Single pixel
+       if(!server->subpixel)
+       {
+               single_pixel(pkg);
+       }
+       else
+// Sub pixel
+       {
+               subpixel(pkg);
+       }
+
+
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+MotionHVScan::MotionHVScan(int total_clients,
+       int total_packages)
+ : LoadServer(
+// DEBUG
+//1, 1
+total_clients, total_packages
+)
+{
+       test_match = 1;
+       downsampled_previous = 0;
+       downsampled_current = 0;
+       rotated_current = 0;
+       rotater = 0;
+}
+
+MotionHVScan::~MotionHVScan()
+{
+       delete downsampled_previous;
+       delete downsampled_current;
+       if(rotated_current)
+       {
+               for(int i = 0; i < total_rotated; i++)
+               {
+                       delete rotated_current[i];
+               }
+
+               delete [] rotated_current;
+       }
+       delete rotater;
+}
+
+
+void MotionHVScan::init_packages()
+{
+// Set package coords
+// Total range of positions to scan with downsampling
+       int downsampled_scan_x1 = scan_x1 / current_downsample;
+       //int downsampled_scan_x2 = scan_x2 / current_downsample;
+       int downsampled_scan_y1 = scan_y1 / current_downsample;
+       //int downsampled_scan_y2 = scan_y2 / current_downsample;
+       int downsampled_block_x1 = block_x1 / current_downsample;
+       int downsampled_block_x2 = block_x2 / current_downsample;
+       int downsampled_block_y1 = block_y1 / current_downsample;
+       int downsampled_block_y2 = block_y2 / current_downsample;
+
+
+//printf("MotionHVScan::init_packages %d %d\n", __LINE__, get_total_packages());
+// printf("MotionHVScan::init_packages %d current_downsample=%d scan_x1=%d scan_x2=%d block_x1=%d block_x2=%d\n",
+// __LINE__,
+// current_downsample,
+// downsampled_scan_x1,
+// downsampled_scan_x2,
+// downsampled_block_x1,
+// downsampled_block_x2);
+// if(current_downsample == 8 && downsampled_scan_x1 == 47)
+// {
+// downsampled_previous->write_png("/tmp/previous");
+// downsampled_current->write_png("/tmp/current");
+// }
+
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               MotionHVScanPackage *pkg = (MotionHVScanPackage*)get_package(i);
+
+               pkg->block_x1 = downsampled_block_x1;
+               pkg->block_x2 = downsampled_block_x2;
+               pkg->block_y1 = downsampled_block_y1;
+               pkg->block_y2 = downsampled_block_y2;
+               pkg->difference1 = 0;
+               pkg->difference2 = 0;
+               pkg->dx = 0;
+               pkg->dy = 0;
+               pkg->valid = 1;
+               pkg->angle_step = 0;
+
+               if(!subpixel)
+               {
+                       if(rotation_pass)
+                       {
+                               pkg->search_x = scan_x1 / current_downsample;
+                               pkg->search_y = scan_y1 / current_downsample;
+                               pkg->angle_step = i;
+                       }
+                       else
+                       {
+
+                               int current_x_step = (i % x_steps);
+                               int current_y_step = (i / x_steps);
+
+       //printf("MotionHVScan::init_packages %d i=%d x_step=%d y_step=%d angle_step=%d\n",
+       //__LINE__, i, current_x_step, current_y_step, current_angle_step);
+                               pkg->search_x = downsampled_scan_x1 + current_x_step *
+                                       (scan_x2 - scan_x1) / current_downsample / x_steps;
+                               pkg->search_y = downsampled_scan_y1 + current_y_step *
+                                       (scan_y2 - scan_y1) / current_downsample / y_steps;
+
+                               if(do_rotate)
+                               {
+                                       pkg->angle_step = angle_steps / 2;
+                               }
+                               else
+                               {
+                                       pkg->angle_step = 0;
+                               }
+                       }
+
+                       pkg->sub_x = 0;
+                       pkg->sub_y = 0;
+               }
+               else
+               {
+                       pkg->sub_x = i % (OVERSAMPLE * SUBPIXEL_RANGE);
+                       pkg->sub_y = i / (OVERSAMPLE * SUBPIXEL_RANGE);
+
+//                     if(horizontal_only)
+//                     {
+//                             pkg->sub_y = 0;
+//                     }
+//
+//                     if(vertical_only)
+//                     {
+//                             pkg->sub_x = 0;
+//                     }
+
+                       pkg->search_x = scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
+                       pkg->search_y = scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
+                       pkg->sub_x %= OVERSAMPLE;
+                       pkg->sub_y %= OVERSAMPLE;
+
+
+
+// printf("MotionHVScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n",
+// __LINE__,
+// i,
+// pkg->search_x,
+// pkg->search_y,
+// pkg->sub_x,
+// pkg->sub_y);
+               }
+
+// printf("MotionHVScan::init_packages %d %d,%d %d,%d %d,%d\n",
+// __LINE__,
+// scan_x1,
+// scan_x2,
+// scan_y1,
+// scan_y2,
+// pkg->search_x,
+// pkg->search_y);
+       }
+}
+
+LoadClient* MotionHVScan::new_client()
+{
+       return new MotionHVScanUnit(this);
+}
+
+LoadPackage* MotionHVScan::new_package()
+{
+       return new MotionHVScanPackage;
+}
+
+
+void MotionHVScan::set_test_match(int value)
+{
+       this->test_match = value;
+}
+
+
+
+
+#define DOWNSAMPLE(type, temp_type, components, max) \
+{ \
+       temp_type r; \
+       temp_type g; \
+       temp_type b; \
+       temp_type a; \
+       type **in_rows = (type**)src->get_rows(); \
+       type **out_rows = (type**)dst->get_rows(); \
+ \
+       for(int i = 0; i < h; i += downsample) \
+       { \
+               int y1 = MAX(i, 0); \
+               int y2 = MIN(i + downsample, h); \
+ \
+ \
+               for(int j = 0; \
+                       j < w; \
+                       j += downsample) \
+               { \
+                       int x1 = MAX(j, 0); \
+                       int x2 = MIN(j + downsample, w); \
+ \
+                       temp_type scale = (x2 - x1) * (y2 - y1); \
+                       if(x2 > x1 && y2 > y1) \
+                       { \
+ \
+/* Read in values */ \
+                               r = 0; \
+                               g = 0; \
+                               b = 0; \
+                               if(components == 4) a = 0; \
+ \
+                               for(int k = y1; k < y2; k++) \
+                               { \
+                                       type *row = in_rows[k] + x1 * components; \
+                                       for(int l = x1; l < x2; l++) \
+                                       { \
+                                               r += *row++; \
+                                               g += *row++; \
+                                               b += *row++; \
+                                               if(components == 4) a += *row++; \
+                                       } \
+                               } \
+ \
+/* Write average */ \
+                               r /= scale; \
+                               g /= scale; \
+                               b /= scale; \
+                               if(components == 4) a /= scale; \
+ \
+                               type *row = out_rows[y1 / downsample] + \
+                                       x1 / downsample * components; \
+                               *row++ = r; \
+                               *row++ = g; \
+                               *row++ = b; \
+                               if(components == 4) *row++ = a; \
+                       } \
+               } \
+/*printf("DOWNSAMPLE 3 %d\n", i);*/ \
+       } \
+}
+
+
+
+
+void MotionHVScan::downsample_frame(VFrame *dst,
+       VFrame *src,
+       int downsample)
+{
+       int h = src->get_h();
+       int w = src->get_w();
+
+//PRINT_TRACE
+//printf("downsample=%d w=%d h=%d dst=%d %d\n", downsample, w, h, dst->get_w(), dst->get_h());
+       switch(src->get_color_model())
+       {
+               case BC_RGB888:
+                       DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
+                       break;
+               case BC_RGB_FLOAT:
+                       DOWNSAMPLE(float, float, 3, 1.0)
+                       break;
+               case BC_RGBA8888:
+                       DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
+                       break;
+               case BC_RGBA_FLOAT:
+                       DOWNSAMPLE(float, float, 4, 1.0)
+                       break;
+               case BC_YUV888:
+                       DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
+                       break;
+               case BC_YUVA8888:
+                       DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
+                       break;
+       }
+//PRINT_TRACE
+}
+
+double MotionHVScan::step_to_angle(int step, double center)
+{
+       if(step < angle_steps / 2)
+       {
+               return center - angle_step * (angle_steps / 2 - step);
+       }
+       else
+       if(step > angle_steps / 2)
+       {
+               return center + angle_step * (step - angle_steps / 2);
+       }
+       else
+       {
+               return center;
+       }
+}
+
+#ifdef STDDEV_TEST
+static int compare(const void *p1, const void *p2)
+{
+       double value1 = *(double*)p1;
+       double value2 = *(double*)p2;
+
+//printf("compare %d value1=%f value2=%f\n", __LINE__, value1, value2);
+       return value1 > value2;
+}
+#endif
+
+// reject vectors based on content.  It's the reason Goog can't stabilize timelapses.
+//#define STDDEV_TEST
+
+// pixel accurate motion search
+void MotionHVScan::pixel_search(int &x_result, int &y_result, double &r_result)
+{
+// reduce level of detail until enough steps
+       while(current_downsample > 1 &&
+               ((block_x2 - block_x1) / current_downsample < MIN_DOWNSAMPLED_SIZE ||
+               (block_y2 - block_y1) / current_downsample < MIN_DOWNSAMPLED_SIZE
+               ||
+                (scan_x2 - scan_x1) / current_downsample < MIN_DOWNSAMPLED_SCAN ||
+               (scan_y2 - scan_y1) / current_downsample < MIN_DOWNSAMPLED_SCAN
+               ))
+       {
+               current_downsample /= 2;
+       }
+
+
+
+// create downsampled images.
+// Need to keep entire frame to search for rotation.
+       int downsampled_prev_w = previous_frame_arg->get_w() / current_downsample;
+       int downsampled_prev_h = previous_frame_arg->get_h() / current_downsample;
+       int downsampled_current_w = current_frame_arg->get_w() / current_downsample;
+       int downsampled_current_h = current_frame_arg->get_h() / current_downsample;
+
+// printf("MotionHVScan::pixel_search %d current_downsample=%d current_frame_arg->get_w()=%d downsampled_current_w=%d\n",
+// __LINE__,
+// current_downsample,
+// current_frame_arg->get_w(),
+// downsampled_current_w);
+
+       x_steps = (scan_x2 - scan_x1) / current_downsample;
+       y_steps = (scan_y2 - scan_y1) / current_downsample;
+
+// in rads
+       double test_angle1 = atan2((double)downsampled_current_h / 2 - 1, (double)downsampled_current_w / 2);
+       double test_angle2 = atan2((double)downsampled_current_h / 2, (double)downsampled_current_w / 2 - 1);
+
+// in deg
+       angle_step = 360.0f * fabs(test_angle1 - test_angle2) / 2 / M_PI;
+
+// printf("MotionHVScan::pixel_search %d test_angle1=%f test_angle2=%f angle_step=%f\n",
+// __LINE__,
+// 360.0f * test_angle1 / 2 / M_PI,
+// 360.0f * test_angle2 / 2 / M_PI,
+// angle_step);
+
+
+       if(do_rotate && angle_step < rotation_range)
+       {
+               angle_steps = 1 + (int)((scan_angle2 - scan_angle1) / angle_step + 0.5);
+       }
+       else
+       {
+               angle_steps = 1;
+       }
+
+
+       if(current_downsample > 1)
+       {
+               if(!downsampled_previous ||
+                       downsampled_previous->get_w() != downsampled_prev_w ||
+                       downsampled_previous->get_h() != downsampled_prev_h)
+               {
+                       delete downsampled_previous;
+                       downsampled_previous = new VFrame();
+                       downsampled_previous->set_use_shm(0);
+                       downsampled_previous->reallocate(0,
+                               -1,
+                               0,
+                               0,
+                               0,
+                               downsampled_prev_w + 1,
+                               downsampled_prev_h + 1,
+                               previous_frame_arg->get_color_model(),
+                               -1);
+               }
+
+               if(!downsampled_current ||
+                       downsampled_current->get_w() != downsampled_current_w ||
+                       downsampled_current->get_h() != downsampled_current_h)
+               {
+                       delete downsampled_current;
+                       downsampled_current = new VFrame();
+                       downsampled_current->set_use_shm(0);
+                       downsampled_current->reallocate(0,
+                               -1,
+                               0,
+                               0,
+                               0,
+                               downsampled_current_w + 1,
+                               downsampled_current_h + 1,
+                               current_frame_arg->get_color_model(),
+                               -1);
+               }
+
+
+               downsample_frame(downsampled_previous,
+                       previous_frame_arg,
+                       current_downsample);
+               downsample_frame(downsampled_current,
+                       current_frame_arg,
+                       current_downsample);
+               previous_frame = downsampled_previous;
+               current_frame = downsampled_current;
+
+       }
+       else
+       {
+               previous_frame = previous_frame_arg;
+               current_frame = current_frame_arg;
+       }
+
+
+
+// printf("MotionHVScan::pixel_search %d x_steps=%d y_steps=%d angle_steps=%d total_steps=%d\n",
+// __LINE__,
+// x_steps,
+// y_steps,
+// angle_steps,
+// total_steps);
+
+
+
+// test variance of constant macroblock
+       int color_model = current_frame->get_color_model();
+       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+       int row_bytes = current_frame->get_bytes_per_line();
+       int block_w = block_x2 - block_x1;
+       int block_h = block_y2 - block_y1;
+
+       unsigned char *current_ptr =
+               current_frame->get_rows()[block_y1 / current_downsample] +
+               (block_x1 / current_downsample) * pixel_size;
+       unsigned char *previous_ptr =
+               previous_frame->get_rows()[scan_y1 / current_downsample] +
+               (scan_x1 / current_downsample) * pixel_size;
+
+
+
+// test detail in prev & current frame
+       double range1 = calculate_range(current_ptr,
+               row_bytes,
+               block_w / current_downsample,
+               block_h / current_downsample,
+               color_model);
+
+       if(range1 < 1)
+       {
+printf("MotionHVScan::pixel_search %d range fail range1=%f\n", __LINE__, range1);
+               failed = 1;
+               return;
+       }
+
+       double range2 = calculate_range(previous_ptr,
+               row_bytes,
+               block_w / current_downsample,
+               block_h / current_downsample,
+               color_model);
+
+       if(range2 < 1)
+       {
+printf("MotionHVScan::pixel_search %d range fail range2=%f\n", __LINE__, range2);
+               failed = 1;
+               return;
+       }
+
+
+// create rotated images
+       if(rotated_current &&
+               (total_rotated != angle_steps ||
+               rotated_current[0]->get_w() != downsampled_current_w ||
+               rotated_current[0]->get_h() != downsampled_current_h))
+       {
+               for(int i = 0; i < total_rotated; i++)
+               {
+                       delete rotated_current[i];
+               }
+
+               delete [] rotated_current;
+               rotated_current = 0;
+               total_rotated = 0;
+       }
+
+       if(do_rotate)
+       {
+               total_rotated = angle_steps;
+
+
+               if(!rotated_current)
+               {
+                       rotated_current = new VFrame*[total_rotated];
+                       bzero(rotated_current, sizeof(VFrame*) * total_rotated);
+               }
+
+// printf("MotionHVScan::pixel_search %d total_rotated=%d w=%d h=%d block_w=%d block_h=%d\n",
+// __LINE__,
+// total_rotated,
+// downsampled_current_w,
+// downsampled_current_h,
+// (block_x2 - block_x1) / current_downsample,
+// (block_y2 - block_y1) / current_downsample);
+               for(int i = 0; i < angle_steps; i++)
+               {
+
+// printf("MotionHVScan::pixel_search %d w=%d h=%d x=%d y=%d angle=%f\n",
+// __LINE__,
+// downsampled_current_w,
+// downsampled_current_h,
+// (block_x1 + block_x2) / 2 / current_downsample,
+// (block_y1 + block_y2) / 2 / current_downsample,
+// step_to_angle(i, r_result));
+
+// printf("MotionHVScan::pixel_search %d i=%d rotated_current[i]=%p\n",
+// __LINE__,
+// i,
+// rotated_current[i]);
+                       if(!rotated_current[i])
+                       {
+                               rotated_current[i] = new VFrame();
+                               rotated_current[i]->set_use_shm(0);
+                               rotated_current[i]->reallocate(0,
+                                       -1,
+                                       0,
+                                       0,
+                                       0,
+                                       downsampled_current_w + 1,
+                                       downsampled_current_h + 1,
+                                       current_frame_arg->get_color_model(),
+                                       -1);
+//printf("MotionHVScan::pixel_search %d\n", __LINE__);
+                       }
+
+
+                       if(!rotater)
+                       {
+                               rotater = new AffineEngine(get_total_clients(),
+                                       get_total_clients());
+                       }
+
+// get smallest viewport size required for the angle
+                       double diag = hypot((block_x2 - block_x1) / current_downsample,
+                               (block_y2 - block_y1) / current_downsample);
+                       double angle1 = atan2(block_y2 - block_y1, block_x2 - block_x1) +
+                               TO_RAD(step_to_angle(i, r_result));
+                       double angle2 = -atan2(block_y2 - block_y1, block_x2 - block_x1) +
+                               TO_RAD(step_to_angle(i, r_result));
+                       double max_horiz = MAX(abs(diag * cos(angle1)), abs(diag * cos(angle2)));
+                       double max_vert = MAX(abs(diag * sin(angle1)), abs(diag * sin(angle2)));
+                       int center_x = (block_x1 + block_x2) / 2 / current_downsample;
+                       int center_y = (block_y1 + block_y2) / 2 / current_downsample;
+                       int x1 = center_x - max_horiz / 2;
+                       int y1 = center_y - max_vert / 2;
+                       int x2 = x1 + max_horiz;
+                       int y2 = y1 + max_vert;
+                       CLAMP(x1, 0, downsampled_current_w - 1);
+                       CLAMP(y1, 0, downsampled_current_h - 1);
+                       CLAMP(x2, 0, downsampled_current_w - 1);
+                       CLAMP(y2, 0, downsampled_current_h - 1);
+
+//printf("MotionHVScan::pixel_search %d %f %f %d %d\n",
+//__LINE__, TO_DEG(angle1), TO_DEG(angle2), (int)max_horiz, (int)max_vert);
+                       rotater->set_in_viewport(x1,
+                               y1,
+                               x2 - x1,
+                               y2 - y1);
+                       rotater->set_out_viewport(x1,
+                               y1,
+                               x2 - x1,
+                               y2 - y1);
+
+//                     rotater->set_in_viewport(0,
+//                             0,
+//                             downsampled_current_w,
+//                             downsampled_current_h);
+//                     rotater->set_out_viewport(0,
+//                             0,
+//                             downsampled_current_w,
+//                             downsampled_current_h);
+
+                       rotater->set_in_pivot(center_x, center_y);
+                       rotater->set_out_pivot(center_x, center_y);
+
+                       rotater->rotate(rotated_current[i],
+                               current_frame,
+                               step_to_angle(i, r_result));
+
+// rotated_current[i]->draw_rect(block_x1 / current_downsample,
+// block_y1 / current_downsample,
+// block_x2 / current_downsample,
+// block_y2 / current_downsample);
+// char string[BCTEXTLEN];
+// sprintf(string, "/tmp/rotated%d", i);
+// rotated_current[i]->write_png(string);
+//downsampled_previous->write_png("/tmp/previous");
+//printf("MotionHVScan::pixel_search %d\n", __LINE__);
+               }
+       }
+
+
+
+
+
+
+// printf("MotionHVScan::pixel_search %d block x=%d y=%d w=%d h=%d\n",
+// __LINE__,
+// block_x1 / current_downsample,
+// block_y1 / current_downsample,
+// block_w / current_downsample,
+// block_h / current_downsample);
+
+
+
+
+
+
+
+//exit(1);
+// Test only translation of the middle rotated frame
+       rotation_pass = 0;
+       total_steps = x_steps * y_steps;
+       set_package_count(total_steps);
+       process_packages();
+
+
+
+
+
+
+// Get least difference
+       int64_t min_difference = -1;
+#ifdef STDDEV_TEST
+       double stddev_table[get_total_packages()];
+#endif
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               MotionHVScanPackage *pkg = (MotionHVScanPackage*)get_package(i);
+
+#ifdef STDDEV_TEST
+               double stddev = sqrt(pkg->difference1) /
+                       (block_w / current_downsample) /
+                       (block_h / current_downsample) /
+                       3;
+// printf("MotionHVScan::pixel_search %d current_downsample=%d search_x=%d search_y=%d diff1=%f\n",
+// __LINE__,
+// current_downsample,
+// pkg->search_x,
+// pkg->search_y,
+// sqrt(pkg->difference1) / block_w / current_downsample / block_h / 3 /* / variance */);
+
+// printf("MotionHVScan::pixel_search %d range1=%f stddev=%f\n",
+// __LINE__,
+// range1,
+// stddev);
+
+               stddev_table[i] = stddev;
+#endif // STDDEV_TEST
+
+               if(pkg->difference1 < min_difference || i == 0)
+               {
+                       min_difference = pkg->difference1;
+                       x_result = pkg->search_x * current_downsample * OVERSAMPLE;
+                       y_result = pkg->search_y * current_downsample * OVERSAMPLE;
+
+// printf("MotionHVScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
+// __LINE__,
+// block_x1 * OVERSAMPLE - x_result,
+// block_y1 * OVERSAMPLE - y_result,
+// pkg->angle_step,
+// pkg->difference1);
+
+               }
+       }
+
+
+#ifdef STDDEV_TEST
+       qsort(stddev_table, get_total_packages(), sizeof(double), compare);
+
+
+// reject motion vector if not similar enough
+//     if(stddev_table[0] > 0.2)
+//     {
+// if(debug)
+// {
+// printf("MotionHVScan::pixel_search %d stddev fail min_stddev=%f\n",
+// __LINE__,
+// stddev_table[0]);
+// }
+//             failed = 1;
+//             return;
+//     }
+
+if(debug)
+{
+       printf("MotionHVScan::pixel_search %d\n", __LINE__);
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               printf("%f\n", stddev_table[i]);
+       }
+}
+
+// reject motion vector if not a sigmoid curve
+// TODO: use linear interpolation
+       int steps = 2;
+       int step = get_total_packages() / steps;
+       double curve[steps];
+       for(int i = 0; i < steps; i++)
+       {
+               int start = get_total_packages() * i / steps;
+               int end = get_total_packages() * (i + 1) / steps;
+               end = MIN(end, get_total_packages() - 1);
+               curve[i] = stddev_table[end] - stddev_table[start];
+       }
+
+
+//     if(curve[0] < (curve[1] * 1.01) ||
+//             curve[2] < (curve[1] * 1.01) ||
+//             curve[0] < (curve[2] * 0.75))
+//     if(curve[0] < curve[1])
+//     {
+// if(debug)
+// {
+// printf("MotionHVScan::pixel_search %d curve fail %f %f\n",
+// __LINE__,
+// curve[0],
+// curve[1]);
+// }
+//             failed = 1;
+//             return;
+//     }
+
+if(debug)
+{
+printf("MotionHVScan::pixel_search %d curve=%f %f ranges=%f %f min_stddev=%f\n",
+__LINE__,
+curve[0],
+curve[1],
+range1,
+range2,
+stddev_table[0]);
+}
+#endif // STDDEV_TEST
+
+
+
+
+
+       if(do_rotate)
+       {
+               rotation_pass = 1;;
+               total_steps = angle_steps;
+               scan_x1 = x_result / OVERSAMPLE;
+               scan_y1 = y_result / OVERSAMPLE;
+               set_package_count(total_steps);
+               process_packages();
+
+
+
+               min_difference = -1;
+               double prev_r_result = r_result;
+               for(int i = 0; i < get_total_packages(); i++)
+               {
+                       MotionHVScanPackage *pkg = (MotionHVScanPackage*)get_package(i);
+
+// printf("MotionHVScan::pixel_search %d search_x=%d search_y=%d angle_step=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
+// __LINE__,
+// pkg->search_x,
+// pkg->search_y,
+// pkg->search_angle_step,
+// pkg->sub_x,
+// pkg->sub_y,
+// pkg->difference1,
+// pkg->difference2);
+                       if(pkg->difference1 < min_difference || i == 0)
+                       {
+                               min_difference = pkg->difference1;
+                               r_result = step_to_angle(i, prev_r_result);
+
+       // printf("MotionHVScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
+       // __LINE__,
+       // block_x1 * OVERSAMPLE - x_result,
+       // block_y1 * OVERSAMPLE - y_result,
+       // pkg->angle_step,
+       // pkg->difference1);
+                       }
+               }
+       }
+
+
+// printf("MotionHVScan::scan_frame %d current_downsample=%d x_result=%f y_result=%f r_result=%f\n",
+// __LINE__,
+// current_downsample,
+// (float)x_result / OVERSAMPLE,
+// (float)y_result / OVERSAMPLE,
+// r_result);
+
+}
+
+
+// subpixel motion search
+void MotionHVScan::subpixel_search(int &x_result, int &y_result)
+{
+       rotation_pass = 0;
+       previous_frame = previous_frame_arg;
+       current_frame = current_frame_arg;
+
+//printf("MotionHVScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
+// Scan every subpixel in a SUBPIXEL_RANGE * SUBPIXEL_RANGE square
+       total_steps = (SUBPIXEL_RANGE * OVERSAMPLE) * (SUBPIXEL_RANGE * OVERSAMPLE);
+
+// These aren't used in subpixel
+       x_steps = OVERSAMPLE * SUBPIXEL_RANGE;
+       y_steps = OVERSAMPLE * SUBPIXEL_RANGE;
+       angle_steps = 1;
+
+       set_package_count(this->total_steps);
+       process_packages();
+
+// Get least difference
+       int64_t min_difference = -1;
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               MotionHVScanPackage *pkg = (MotionHVScanPackage*)get_package(i);
+//printf("MotionHVScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
+//__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
+               if(pkg->difference1 < min_difference || min_difference == -1)
+               {
+                       min_difference = pkg->difference1;
+
+// The sub coords are 1 pixel up & left of the block coords
+                       x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
+                       y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
+
+
+// Fill in results
+                       dx_result = block_x1 * OVERSAMPLE - x_result;
+                       dy_result = block_y1 * OVERSAMPLE - y_result;
+//printf("MotionHVScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
+//__LINE__, dx_result, dy_result, min_difference);
+               }
+
+               if(pkg->difference2 < min_difference)
+               {
+                       min_difference = pkg->difference2;
+
+                       x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x;
+                       y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y;
+
+                       dx_result = block_x1 * OVERSAMPLE - x_result;
+                       dy_result = block_y1 * OVERSAMPLE - y_result;
+//printf("MotionHVScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
+//__LINE__, dx_result, dy_result, min_difference);
+               }
+       }
+}
+
+
+void MotionHVScan::scan_frame(VFrame *previous_frame,
+       VFrame *current_frame,
+       int global_range_w,
+       int global_range_h,
+       int global_block_w,
+       int global_block_h,
+       int block_x,
+       int block_y,
+       int frame_type,
+       int tracking_type,
+       int action_type,
+       int horizontal_only,
+       int vertical_only,
+       int source_position,
+       int total_dx,
+       int total_dy,
+       int global_origin_x,
+       int global_origin_y,
+       int do_motion,
+       int do_rotate,
+       double rotation_center,
+       double rotation_range)
+{
+       this->previous_frame_arg = previous_frame;
+       this->current_frame_arg = current_frame;
+       this->horizontal_only = horizontal_only;
+       this->vertical_only = vertical_only;
+       this->previous_frame = previous_frame_arg;
+       this->current_frame = current_frame_arg;
+       this->global_origin_x = global_origin_x;
+       this->global_origin_y = global_origin_y;
+       this->action_type = action_type;
+       this->do_motion = do_motion;
+       this->do_rotate = do_rotate;
+       this->rotation_center = rotation_center;
+       this->rotation_range = rotation_range;
+
+//printf("MotionHVScan::scan_frame %d\n", __LINE__);
+       dx_result = 0;
+       dy_result = 0;
+       dr_result = 0;
+       failed = 0;
+
+       subpixel = 0;
+// starting level of detail
+// TODO: base it on a table of resolutions
+       current_downsample = STARTING_DOWNSAMPLE;
+       angle_step = 0;
+
+// Single macroblock
+       int w = current_frame->get_w();
+       int h = current_frame->get_h();
+
+// Initial search parameters
+       scan_w = global_range_w;
+       scan_h = global_range_h;
+
+       int block_w = global_block_w;
+       int block_h = global_block_h;
+
+// printf("MotionHVScan::scan_frame %d %d %d %d %d %d %d %d %d\n",
+// __LINE__,
+// global_range_w,
+// global_range_h,
+// global_block_w,
+// global_block_h,
+// scan_w,
+// scan_h,
+// block_w,
+// block_h);
+
+// Location of block in previous frame
+       block_x1 = (int)(block_x - block_w / 2);
+       block_y1 = (int)(block_y - block_h / 2);
+       block_x2 = (int)(block_x + block_w / 2);
+       block_y2 = (int)(block_y + block_h / 2);
+
+// Offset to location of previous block.  This offset needn't be very accurate
+// since it's the offset of the previous image and current image we want.
+       if(frame_type == MotionHVScan::TRACK_PREVIOUS)
+       {
+               block_x1 += total_dx / OVERSAMPLE;
+               block_y1 += total_dy / OVERSAMPLE;
+               block_x2 += total_dx / OVERSAMPLE;
+               block_y2 += total_dy / OVERSAMPLE;
+       }
+
+       skip = 0;
+
+       switch(tracking_type)
+       {
+// Don't calculate
+               case MotionHVScan::NO_CALCULATE:
+                       dx_result = 0;
+                       dy_result = 0;
+                       dr_result = rotation_center;
+                       skip = 1;
+                       break;
+
+               case MotionHVScan::LOAD:
+               {
+// Load result from disk
+                       char string[BCTEXTLEN];
+
+                       skip = 1;
+                       if(do_motion)
+                       {
+                               sprintf(string, "%s%06d",
+                                       MOTION_FILE,
+                                       source_position);
+//printf("MotionHVScan::scan_frame %d %s\n", __LINE__, string);
+                               FILE *input = fopen(string, "r");
+                               if(input)
+                               {
+                                       int temp = fscanf(input,
+                                               "%d %d",
+                                               &dx_result,
+                                               &dy_result);
+                                       if( temp != 2 )
+                                               printf("MotionHVScan::scan_frame %d %s\n", __LINE__, string);
+// HACK
+//dx_result *= 2;
+//dy_result *= 2;
+//printf("MotionHVScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
+                                       fclose(input);
+                               }
+                               else
+                               {
+                                       skip = 0;
+                               }
+                       }
+
+                       if(do_rotate)
+                       {
+                               sprintf(string,
+                                       "%s%06d",
+                                       ROTATION_FILE,
+                                       source_position);
+                               FILE *input = fopen(string, "r");
+                               if(input)
+                               {
+                                       int temp = fscanf(input, "%f", &dr_result);
+                                       if( temp != 1 )
+                                               printf("MotionHVScan::scan_frame %d %s\n", __LINE__, string);
+// DEBUG
+//dr_result += 0.25;
+                                       fclose(input);
+                               }
+                               else
+                               {
+                                       skip = 0;
+                               }
+                       }
+                       break;
+               }
+
+// Scan from scratch
+               default:
+                       skip = 0;
+                       break;
+       }
+
+
+
+       if(!skip && test_match)
+       {
+               if(previous_frame->data_matches(current_frame))
+               {
+printf("MotionHVScan::scan_frame: data matches. skipping.\n");
+                       dx_result = 0;
+                       dy_result = 0;
+                       dr_result = rotation_center;
+                       skip = 1;
+               }
+       }
+
+
+// Perform scan
+       if(!skip)
+       {
+// Location of block in current frame
+               int origin_offset_x = this->global_origin_x;
+               int origin_offset_y = this->global_origin_y;
+               int x_result = block_x1 + origin_offset_x;
+               int y_result = block_y1 + origin_offset_y;
+               double r_result = rotation_center;
+
+// printf("MotionHVScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
+// block_x1 + block_w / 2,
+// block_y1 + block_h / 2,
+// block_w,
+// block_h,
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2);
+
+               while(!failed)
+               {
+                       scan_x1 = x_result - scan_w / 2;
+                       scan_y1 = y_result - scan_h / 2;
+                       scan_x2 = x_result + scan_w / 2;
+                       scan_y2 = y_result + scan_h / 2;
+                       scan_angle1 = r_result - rotation_range;
+                       scan_angle2 = r_result + rotation_range;
+
+
+
+// Zero out requested values
+//                     if(horizontal_only)
+//                     {
+//                             scan_y1 = block_y1;
+//                             scan_y2 = block_y1 + 1;
+//                     }
+//                     if(vertical_only)
+//                     {
+//                             scan_x1 = block_x1;
+//                             scan_x2 = block_x1 + 1;
+//                     }
+
+// printf("MotionHVScan::scan_frame %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n",
+// __LINE__,
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// scan_x1,
+// scan_y1,
+// scan_x2,
+// scan_y2);
+
+
+// Clamp the block coords before the scan so we get useful scan coords.
+                       clamp_scan(w,
+                               h,
+                               &block_x1,
+                               &block_y1,
+                               &block_x2,
+                               &block_y2,
+                               &scan_x1,
+                               &scan_y1,
+                               &scan_x2,
+                               &scan_y2,
+                               0);
+
+
+// printf("MotionHVScan::scan_frame %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_result=%d y_result=%d\n",
+// __LINE__,
+// block_x1,
+// block_y1,
+// block_x2,
+// block_y2,
+// scan_x1,
+// scan_y1,
+// scan_x2,
+// scan_y2,
+// x_result,
+// y_result);
+//if(y_result == 88) exit(0);
+
+
+// Give up if invalid coords.
+                       if(scan_y2 <= scan_y1 ||
+                               scan_x2 <= scan_x1 ||
+                               block_x2 <= block_x1 ||
+                               block_y2 <= block_y1)
+                       {
+                               break;
+                       }
+
+// For subpixel, the top row and left column are skipped
+                       if(subpixel)
+                       {
+
+                               subpixel_search(x_result, y_result);
+// printf("MotionHVScan::scan_frame %d x_result=%d y_result=%d\n",
+// __LINE__,
+// x_result / OVERSAMPLE,
+// y_result / OVERSAMPLE);
+
+                               break;
+                       }
+                       else
+// Single pixel
+                       {
+                               pixel_search(x_result, y_result, r_result);
+//printf("MotionHVScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result / OVERSAMPLE, y_result / OVERSAMPLE);
+
+                               if(failed)
+                               {
+                                       dr_result = 0;
+                                       dx_result = 0;
+                                       dy_result = 0;
+                               }
+                               else
+                               if(current_downsample <= 1)
+                               {
+                       // Single pixel accuracy reached.  Now do exhaustive subpixel search.
+                                       if(action_type == MotionHVScan::STABILIZE ||
+                                               action_type == MotionHVScan::TRACK ||
+                                               action_type == MotionHVScan::NOTHING)
+                                       {
+                                               x_result /= OVERSAMPLE;
+                                               y_result /= OVERSAMPLE;
+//printf("MotionHVScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result, y_result);
+                                               scan_w = SUBPIXEL_RANGE;
+                                               scan_h = SUBPIXEL_RANGE;
+// Final R result
+                                               dr_result = rotation_center - r_result;
+                                               subpixel = 1;
+                                       }
+                                       else
+                                       {
+// Fill in results and quit
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+                                               dr_result = rotation_center - r_result;
+                                               break;
+                                       }
+                               }
+                               else
+// Reduce scan area and try again
+                               {
+//                                     scan_w = (scan_x2 - scan_x1) / 2;
+//                                     scan_h = (scan_y2 - scan_y1) / 2;
+// need slightly more than 2x downsampling factor
+
+                                       if(current_downsample * 3 < scan_w &&
+                                               current_downsample * 3 < scan_h)
+                                       {
+                                               scan_w = current_downsample * 3;
+                                               scan_h = current_downsample * 3;
+                                       }
+
+                                       if(angle_step * 1.5 < rotation_range)
+                                       {
+                                               rotation_range = angle_step * 1.5;
+                                       }
+//printf("MotionHVScan::scan_frame %d %f %f\n", __LINE__, angle_step, rotation_range);
+
+                                       current_downsample /= 2;
+
+// convert back to pixels
+                                       x_result /= OVERSAMPLE;
+                                       y_result /= OVERSAMPLE;
+// debug
+//exit(1);
+                               }
+
+                       }
+               }
+
+               dx_result *= -1;
+               dy_result *= -1;
+               dr_result *= -1;
+       }
+// printf("MotionHVScan::scan_frame %d dx=%f dy=%f dr=%f\n",
+// __LINE__,
+// (float)dx_result / OVERSAMPLE,
+// (float)dy_result / OVERSAMPLE,
+// dr_result);
+
+
+
+
+// Write results
+       if(!skip && tracking_type == MotionHVScan::SAVE)
+       {
+               char string[BCTEXTLEN];
+
+
+               if(do_motion)
+               {
+                       sprintf(string,
+                               "%s%06d",
+                               MOTION_FILE,
+                               source_position);
+                       FILE *output = fopen(string, "w");
+                       if(output)
+                       {
+                               fprintf(output,
+                                       "%d %d\n",
+                                       dx_result,
+                                       dy_result);
+                               fclose(output);
+                       }
+                       else
+                       {
+                               printf("MotionHVScan::scan_frame %d: save motion failed\n", __LINE__);
+                       }
+               }
+
+               if(do_rotate)
+               {
+                       sprintf(string,
+                               "%s%06d",
+                               ROTATION_FILE,
+                               source_position);
+                       FILE *output = fopen(string, "w");
+                       if(output)
+                       {
+                               fprintf(output, "%f\n", dr_result);
+                               fclose(output);
+                       }
+                       else
+                       {
+                               printf("MotionHVScan::scan_frame %d save rotation failed\n", __LINE__);
+                       }
+               }
+       }
+
+
+       if(vertical_only) dx_result = 0;
+       if(horizontal_only) dy_result = 0;
+
+// printf("MotionHVScan::scan_frame %d dx=%d dy=%d\n",
+// __LINE__,
+// this->dx_result,
+// this->dy_result);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define ABS_DIFF(type, temp_type, multiplier, components) \
+{ \
+       temp_type result_temp = 0; \
+       for(int i = 0; i < h; i++) \
+       { \
+               type *prev_row = (type*)prev_ptr; \
+               type *current_row = (type*)current_ptr; \
+               for(int j = 0; j < w; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               temp_type difference; \
+                               difference = *prev_row++ - *current_row++; \
+                               difference *= difference; \
+                               result_temp += difference; \
+                       } \
+                       if(components == 4) \
+                       { \
+                               prev_row++; \
+                               current_row++; \
+                       } \
+               } \
+               prev_ptr += row_bytes; \
+               current_ptr += row_bytes; \
+       } \
+       result = (int64_t)(result_temp * multiplier); \
+}
+
+int64_t MotionHVScan::abs_diff(unsigned char *prev_ptr,
+       unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model)
+{
+       int64_t result = 0;
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       ABS_DIFF(float, double, 0x10000, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       ABS_DIFF(float, double, 0x10000, 4)
+                       break;
+               case BC_YUV888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       ABS_DIFF(unsigned char, int64_t, 1, 4)
+                       break;
+       }
+       return result;
+}
+
+
+
+#define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
+{ \
+       temp_type result_temp = 0; \
+       temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
+       temp_type y1_fraction = 0x100 - y2_fraction; \
+       temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
+       temp_type x1_fraction = 0x100 - x2_fraction; \
+       for(int i = 0; i < h_sub; i++) \
+       { \
+               type *prev_row1 = (type*)prev_ptr; \
+               type *prev_row2 = (type*)prev_ptr + components; \
+               type *prev_row3 = (type*)(prev_ptr + row_bytes); \
+               type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
+               type *current_row = (type*)current_ptr; \
+               for(int j = 0; j < w_sub; j++) \
+               { \
+/* Scan each component */ \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               temp_type difference; \
+                               temp_type prev_value = \
+                                       (*prev_row1++ * x1_fraction * y1_fraction + \
+                                       *prev_row2++ * x2_fraction * y1_fraction + \
+                                       *prev_row3++ * x1_fraction * y2_fraction + \
+                                       *prev_row4++ * x2_fraction * y2_fraction) / \
+                                       0x100 / 0x100; \
+                               temp_type current_value = *current_row++; \
+                               difference = prev_value - current_value; \
+                               difference *= difference; \
+                               result_temp += difference; \
+                       } \
+ \
+/* skip alpha */ \
+                       if(components == 4) \
+                       { \
+                               prev_row1++; \
+                               prev_row2++; \
+                               prev_row3++; \
+                               prev_row4++; \
+                               current_row++; \
+                       } \
+               } \
+               prev_ptr += row_bytes; \
+               current_ptr += row_bytes; \
+       } \
+       result = (int64_t)(result_temp * multiplier); \
+}
+
+
+
+
+int64_t MotionHVScan::abs_diff_sub(unsigned char *prev_ptr,
+       unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model,
+       int sub_x,
+       int sub_y)
+{
+       int h_sub = h - 1;
+       int w_sub = w - 1;
+       int64_t result = 0;
+
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       ABS_DIFF_SUB(float, double, 0x10000, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       ABS_DIFF_SUB(float, double, 0x10000, 4)
+                       break;
+               case BC_YUV888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
+                       break;
+       }
+       return result;
+}
+
+
+#if 0
+#define VARIANCE(type, temp_type, multiplier, components) \
+{ \
+       temp_type average[3] = { 0 }; \
+       temp_type variance[3] = { 0 }; \
+ \
+       for(int i = 0; i < h; i++) \
+       { \
+               type *row = (type*)current_ptr + i * row_bytes; \
+               for(int j = 0; j < w; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               average[k] += row[k]; \
+                       } \
+                       row += components; \
+               } \
+       } \
+       for(int k = 0; k < 3; k++) \
+       { \
+               average[k] /= w * h; \
+       } \
+ \
+       for(int i = 0; i < h; i++) \
+       { \
+               type *row = (type*)current_ptr + i * row_bytes; \
+               for(int j = 0; j < w; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               variance[k] += SQR(row[k] - average[k]); \
+                       } \
+                       row += components; \
+               } \
+       } \
+       result = (double)multiplier * \
+               sqrt((variance[0] + variance[1] + variance[2]) / w / h / 3); \
+}
+
+double MotionHVScan::calculate_variance(unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model)
+{
+       double result = 0;
+
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       VARIANCE(unsigned char, int, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       VARIANCE(unsigned char, int, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       VARIANCE(float, double, 255, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       VARIANCE(float, double, 255, 4)
+                       break;
+               case BC_YUV888:
+                       VARIANCE(unsigned char, int, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       VARIANCE(unsigned char, int, 1, 4)
+                       break;
+       }
+
+
+       return result;
+}
+#endif // 0
+
+
+
+
+#define RANGE(type, temp_type, multiplier, components) \
+{ \
+       temp_type min[3]; \
+       temp_type max[3]; \
+       min[0] = 0x7fff; \
+       min[1] = 0x7fff; \
+       min[2] = 0x7fff; \
+       max[0] = 0; \
+       max[1] = 0; \
+       max[2] = 0; \
+ \
+       for(int i = 0; i < h; i++) \
+       { \
+               type *row = (type*)current_ptr + i * row_bytes; \
+               for(int j = 0; j < w; j++) \
+               { \
+                       for(int k = 0; k < 3; k++) \
+                       { \
+                               if(row[k] > max[k]) max[k] = row[k]; \
+                               if(row[k] < min[k]) min[k] = row[k]; \
+                       } \
+                       row += components; \
+               } \
+       } \
+ \
+       for(int k = 0; k < 3; k++) \
+       { \
+               /* printf("MotionHVScan::calculate_range %d k=%d max=%d min=%d\n", __LINE__, k, max[k], min[k]); */ \
+               if(max[k] - min[k] > result) result = max[k] - min[k]; \
+       } \
+ \
+}
+
+double MotionHVScan::calculate_range(unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model)
+{
+       double result = 0;
+
+       switch(color_model)
+       {
+               case BC_RGB888:
+                       RANGE(unsigned char, int, 1, 3)
+                       break;
+               case BC_RGBA8888:
+                       RANGE(unsigned char, int, 1, 4)
+                       break;
+               case BC_RGB_FLOAT:
+                       RANGE(float, float, 255, 3)
+                       break;
+               case BC_RGBA_FLOAT:
+                       RANGE(float, float, 255, 4)
+                       break;
+               case BC_YUV888:
+                       RANGE(unsigned char, int, 1, 3)
+                       break;
+               case BC_YUVA8888:
+                       RANGE(unsigned char, int, 1, 4)
+                       break;
+       }
+
+
+       return result;
+}
+
+
+//#define CLAMP_BLOCK
+
+// this truncates the scan area but not the macroblock unless the macro is defined
+void MotionHVScan::clamp_scan(int w,
+       int h,
+       int *block_x1,
+       int *block_y1,
+       int *block_x2,
+       int *block_y2,
+       int *scan_x1,
+       int *scan_y1,
+       int *scan_x2,
+       int *scan_y2,
+       int use_absolute)
+{
+// printf("MotionHVMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w,
+// h,
+// *block_x1,
+// *block_y1,
+// *block_x2,
+// *block_y2,
+// *scan_x1,
+// *scan_y1,
+// *scan_x2,
+// *scan_y2,
+// use_absolute);
+
+       if(use_absolute)
+       {
+// Limit size of scan area
+// Used for drawing vectors
+// scan is always out of range before block.
+               if(*scan_x1 < 0)
+               {
+#ifdef CLAMP_BLOCK
+                       int difference = -*scan_x1;
+                       *block_x1 += difference;
+#endif
+                       *scan_x1 = 0;
+               }
+
+               if(*scan_y1 < 0)
+               {
+#ifdef CLAMP_BLOCK
+                       int difference = -*scan_y1;
+                       *block_y1 += difference;
+#endif
+                       *scan_y1 = 0;
+               }
+
+               if(*scan_x2 > w)
+               {
+                       int difference = *scan_x2 - w;
+#ifdef CLAMP_BLOCK
+                       *block_x2 -= difference;
+#endif
+                       *scan_x2 -= difference;
+               }
+
+               if(*scan_y2 > h)
+               {
+                       int difference = *scan_y2 - h;
+#ifdef CLAMP_BLOCK
+                       *block_y2 -= difference;
+#endif
+                       *scan_y2 -= difference;
+               }
+
+               CLAMP(*scan_x1, 0, w);
+               CLAMP(*scan_y1, 0, h);
+               CLAMP(*scan_x2, 0, w);
+               CLAMP(*scan_y2, 0, h);
+       }
+       else
+       {
+// Limit range of upper left block coordinates
+// Used for motion tracking
+               if(*scan_x1 < 0)
+               {
+                       int difference = -*scan_x1;
+#ifdef CLAMP_BLOCK
+                       *block_x1 += difference;
+#endif
+                       *scan_x2 += difference;
+                       *scan_x1 = 0;
+               }
+
+               if(*scan_y1 < 0)
+               {
+                       int difference = -*scan_y1;
+#ifdef CLAMP_BLOCK
+                       *block_y1 += difference;
+#endif
+                       *scan_y2 += difference;
+                       *scan_y1 = 0;
+               }
+
+               if(*scan_x2 - *block_x1 + *block_x2 > w)
+               {
+                       int difference = *scan_x2 - *block_x1 + *block_x2 - w;
+                       *scan_x2 -= difference;
+#ifdef CLAMP_BLOCK
+                       *block_x2 -= difference;
+#endif
+               }
+
+               if(*scan_y2 - *block_y1 + *block_y2 > h)
+               {
+                       int difference = *scan_y2 - *block_y1 + *block_y2 - h;
+                       *scan_y2 -= difference;
+#ifdef CLAMP_BLOCK
+                       *block_y2 -= difference;
+#endif
+               }
+
+//             CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
+//             CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
+//             CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
+//             CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
+       }
+
+// Sanity checks which break the calculation but should never happen if the
+// center of the block is inside the frame.
+       CLAMP(*block_x1, 0, w);
+       CLAMP(*block_x2, 0, w);
+       CLAMP(*block_y1, 0, h);
+       CLAMP(*block_y2, 0, h);
+
+// printf("MotionHVMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w,
+// h,
+// *block_x1,
+// *block_y1,
+// *block_x2,
+// *block_y2,
+// *scan_x1,
+// *scan_y1,
+// *scan_x2,
+// *scan_y2,
+// use_absolute);
+}
+
+
+
similarity index 62%
rename from cinelerra-5.1/plugins/motion.new/motionscan.h
rename to cinelerra-5.1/plugins/motion-hv/motionscan-hv.h
index 7bee1222e69e48d4dec55ef44a0f2a1d31374437..7511e64223b25d66a280e1f912cc102669a3ad4d 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 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
 #define MOTIONSCAN_H
 
 
-#include "arraylist.h"
-//#include "../downsample/downsampleengine.inc"
+#include "affine.inc"
 #include "loadbalance.h"
 #include "vframe.inc"
 #include <stdint.h>
 
-class MotionScan;
+class MotionHVScan;
 
 #define OVERSAMPLE 4
-#define MOTION_FILE "/tmp/motion"
+#define MOTION_FILE "/tmp/m"
+#define ROTATION_FILE "/tmp/r"
 
-class MotionScanPackage : public LoadPackage
+class MotionHVScanPackage : public LoadPackage
 {
 public:
-       MotionScanPackage();
+       MotionHVScanPackage();
 
 // For multiple blocks
-// Position of stationary block
+// Position of stationary block after downsampling
        int block_x1, block_y1, block_x2, block_y2;
-// Range of positions to scan
-       int scan_x1, scan_y1, scan_x2, scan_y2;
+// index of rotated frame
+       int angle_step;
+
        int dx;
        int dy;
        int64_t max_difference;
@@ -51,11 +52,9 @@ public:
        int64_t min_pixel;
        int is_border;
        int valid;
-// For single block
-       int step;
        int64_t difference1;
        int64_t difference2;
-// Search position to nearest pixel
+// Search position of current package to nearest pixel with downsampling
        int search_x;
        int search_y;
 // Subpixel of search position
@@ -63,38 +62,27 @@ public:
        int sub_y;
 };
 
-class MotionScanCache
+class MotionHVScanUnit : public LoadClient
 {
 public:
-       MotionScanCache(int x, int y, int64_t difference);
-       int x, y;
-       int64_t difference;
-};
-
-class MotionScanUnit : public LoadClient
-{
-public:
-       MotionScanUnit(MotionScan *server);
-       ~MotionScanUnit();
+       MotionHVScanUnit(MotionHVScan *server);
+       ~MotionHVScanUnit();
 
        void process_package(LoadPackage *package);
-       int64_t get_cache(int x, int y);
-       void put_cache(int x, int y, int64_t difference);
-
-       MotionScan *server;
+       void subpixel(MotionHVScanPackage *pkg);
+       void single_pixel(MotionHVScanPackage *pkg);
 
-       ArrayList<MotionScanCache*> cache;
-       Mutex *cache_lock;
+       MotionHVScan *server;
 };
 
-class MotionScan : public LoadServer
+class MotionHVScan : public LoadServer
 {
 public:
-       MotionScan(int total_clients,
+       MotionHVScan(int total_clients,
                int total_packages);
-       ~MotionScan();
+       ~MotionHVScan();
 
-       friend class MotionScanUnit;
+       friend class MotionHVScanUnit;
 
        void init_packages();
        LoadClient* new_client();
@@ -105,27 +93,27 @@ public:
 // Invoke the motion engine for a search
 // Frame before motion
        void scan_frame(VFrame *previous_frame,
-// Frame after motion
                VFrame *current_frame,
-               int global_range_w,
+               int global_range_w, // in pixels
                int global_range_h,
-               int global_block_w,
+               int global_block_w, // in pixels
                int global_block_h,
-               double block_x,
-               double block_y,
+               int block_x, // in pixels
+               int block_y,
                int frame_type,
                int tracking_type,
                int action_type,
                int horizontal_only,
                int vertical_only,
                int source_position,
-               int total_steps,
-               int total_dx,
+               int total_dx, // in pixels * OVERSAMPLE
                int total_dy,
-               int global_origin_x,
-               int global_origin_y);
-       int64_t get_cache(int x, int y);
-       void put_cache(int x, int y, int64_t difference);
+               int global_origin_x, // in pixels
+               int global_origin_y,
+               int do_motion,
+               int do_rotate,
+               double rotation_center, // in deg
+               double rotation_range);
 
        static int64_t abs_diff(unsigned char *prev_ptr,
                unsigned char *current_ptr,
@@ -159,6 +147,7 @@ public:
 // OVERSAMPLE
        int dx_result;
        int dy_result;
+       float dr_result;
 
        enum
        {
@@ -188,6 +177,27 @@ public:
        };
 
 private:
+       void downsample_frame(VFrame *dst,
+               VFrame *src,
+               int downsample);
+       void pixel_search(int &x_result, int &y_result, double &r_result);
+       void subpixel_search(int &x_result, int &y_result);
+       double step_to_angle(int step, double center);
+
+//     double calculate_variance(unsigned char *current_ptr,
+//             int row_bytes,
+//             int w,
+//             int h,
+//             int color_model);
+       double calculate_range(unsigned char *current_ptr,
+               int row_bytes,
+               int w,
+               int h,
+               int color_model);
+
+
+
+       AffineEngine *rotater;
 // Pointer to downsampled frame before motion
        VFrame *previous_frame;
 // Pointer to downsampled frame after motion
@@ -198,33 +208,49 @@ private:
 // Downsampled frames
        VFrame *downsampled_previous;
        VFrame *downsampled_current;
+// rotated versions of current_frame
+       VFrame **rotated_current;
+// allocation of rotated_current array, a copy of angle_steps
+       int total_rotated;
 // Test for identical frames before processing
 // Faster to skip it if the frames are usually different
        int test_match;
        int skip;
+// macroblocks didn't have enough data
+       int failed;
 // For single block
        int block_x1;
        int block_x2;
        int block_y1;
        int block_y2;
+       int scan_w;
+       int scan_h;
        int scan_x1;
        int scan_y1;
        int scan_x2;
        int scan_y2;
-       int total_pixels;
-       int total_steps;
-       int edge_steps;
+       double scan_angle1, scan_angle2;
        int y_steps;
        int x_steps;
+       int angle_steps;
+// in deg
+       double angle_step;
        int subpixel;
        int horizontal_only;
        int vertical_only;
        int global_origin_x;
        int global_origin_y;
-
-       ArrayList<MotionScanCache*> cache;
-       Mutex *cache_lock;
-//     DownSampleServer *downsample;
+       int action_type;
+       int current_downsample;
+       int downsampled_w;
+       int downsampled_h;
+       int total_steps;
+       int do_motion;
+       int do_rotate;
+       int rotation_pass;
+// in deg
+       double rotation_center;
+       double rotation_range;
 };
 
 
similarity index 92%
rename from cinelerra-5.1/plugins/motion.new/motionscan.inc
rename to cinelerra-5.1/plugins/motion-hv/motionscan-hv.inc
index 4e8229edf2b3788772a82204b79fa0b0fdbeb43a..dd2e376bc28aa6fef11c2b7c8c3f552727a17270 100644 (file)
  *
  */
 
-#ifndef MOTIONSCAN_INC
-#define MOTIONSCAN_INC
+#ifndef MOTIONSCANHV_INC
+#define MOTIONSCANHV_INC
 
 
 
 
-class MotionScan;
+class MotionHVScan;
 
 
 
similarity index 60%
rename from cinelerra-5.1/plugins/motion.new/motionwindow.C
rename to cinelerra-5.1/plugins/motion-hv/motionwindow-hv.C
index 26d7075a3bfa76e27eb5158b2c893d8f747bc6df..ad536ba5752aad8181168bb96f3e65802575a60b 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 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
@@ -22,9 +22,9 @@
 #include "bcdisplayinfo.h"
 #include "clip.h"
 #include "language.h"
-#include "motion.h"
-#include "motionscan.h"
-#include "motionwindow.h"
+#include "motion-hv.h"
+#include "motionscan-hv.h"
+#include "motionwindow-hv.h"
 
 
 
 
 
 
-MotionWindow::MotionWindow(MotionMain *plugin)
- : PluginClientWindow(plugin,
-       600,
-       650,
-       600,
-       650,
-       0)
+MotionHVWindow::MotionHVWindow(MotionHVMain *plugin)
+ : PluginClientWindow(plugin, 600, 650, 600, 650, 0)
 {
        this->plugin = plugin;
 }
 
-MotionWindow::~MotionWindow()
+MotionHVWindow::~MotionHVWindow()
 {
 }
 
-void MotionWindow::create_objects()
+void MotionHVWindow::create_objects()
 {
        int x1 = 10, x = 10, y = 10;
        int x2 = 310;
@@ -58,12 +53,12 @@ void MotionWindow::create_objects()
 
 
 
-       add_subwindow(global = new MotionGlobal(plugin,
-               this,
-               x1,
-               y));
+//     add_subwindow(global = new MotionHVGlobal(plugin,
+//             this,
+//             x1,
+//             y));
 
-       add_subwindow(rotate = new MotionRotate(plugin,
+       add_subwindow(rotate = new MotionHVRotate(plugin,
                this,
                x2,
                y));
@@ -101,32 +96,32 @@ void MotionWindow::create_objects()
                y,
                &plugin->config.global_block_h));
 
-       add_subwindow(title = new BC_Title(x2,
-               y,
-               _("Rotation block size:\n(W/H Percent of image)")));
-       add_subwindow(rotation_block_w = new BlockSize(plugin,
-               x2 + title->get_w() + 10,
-               y,
-               &plugin->config.rotation_block_w));
-       add_subwindow(rotation_block_h = new BlockSize(plugin,
-               x2 + title->get_w() + 10 + rotation_block_w->get_w(),
-               y,
-               &plugin->config.rotation_block_h));
-
-       y += 50;
-       add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
-       add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
-               x1 + title->get_w() + 10,
-               y,
-               80));
-       global_search_positions->create_objects();
-
-       add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
-       add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
-               x2 + title->get_w() + 10,
-               y,
-               80));
-       rotation_search_positions->create_objects();
+//     add_subwindow(title = new BC_Title(x2,
+//             y,
+//             _("Rotation block size:\n(W/H Percent of image)")));
+//     add_subwindow(rotation_block_w = new BlockSize(plugin,
+//             x2 + title->get_w() + 10,
+//             y,
+//             &plugin->config.rotation_block_w));
+//     add_subwindow(rotation_block_h = new BlockSize(plugin,
+//             x2 + title->get_w() + 10 + rotation_block_w->get_w(),
+//             y,
+//             &plugin->config.rotation_block_h));
+
+//     y += 50;
+//     add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
+//     add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
+//             x1 + title->get_w() + 10,
+//             y,
+//             80));
+//     global_search_positions->create_objects();
+//
+//     add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
+//     add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
+//             x2 + title->get_w() + 10,
+//             y,
+//             80));
+//     rotation_search_positions->create_objects();
 
        y += 50;
        add_subwindow(title = new BC_Title(x, y, _("Translation direction:")));
@@ -138,11 +133,11 @@ void MotionWindow::create_objects()
 
        y += 40;
        add_subwindow(title = new BC_Title(x, y + 10, _("Block X:")));
-       add_subwindow(block_x = new MotionBlockX(plugin,
+       add_subwindow(block_x = new MotionHVBlockX(plugin,
                this,
                x + title->get_w() + 10,
                y));
-       add_subwindow(block_x_text = new MotionBlockXText(plugin,
+       add_subwindow(block_x_text = new MotionHVBlockXText(plugin,
                this,
                x + title->get_w() + 10 + block_x->get_w() + 10,
                y + 10));
@@ -157,46 +152,46 @@ void MotionWindow::create_objects()
        int y1 = y;
        y += 50;
        add_subwindow(title = new BC_Title(x2, y + 10, _("Maximum angle offset:")));
-       add_subwindow(rotate_magnitude = new MotionRMagnitude(plugin,
+       add_subwindow(rotate_magnitude = new MotionHVRMagnitude(plugin,
                x2 + title->get_w() + 10,
                y));
 
        y += 40;
        add_subwindow(title = new BC_Title(x2, y + 10, _("Rotation settling speed:")));
-       add_subwindow(rotate_return_speed = new MotionRReturnSpeed(plugin,
+       add_subwindow(rotate_return_speed = new MotionHVRReturnSpeed(plugin,
                x2 + title->get_w() + 10,
                y));
 
 
 
-
+       y = y1;
        y += 40;
        add_subwindow(title = new BC_Title(x, y + 10, _("Block Y:")));
-       add_subwindow(block_y = new MotionBlockY(plugin,
+       add_subwindow(block_y = new MotionHVBlockY(plugin,
                this,
                x + title->get_w() + 10,
                y));
-       add_subwindow(block_y_text = new MotionBlockYText(plugin,
+       add_subwindow(block_y_text = new MotionHVBlockYText(plugin,
                this,
                x + title->get_w() + 10 + block_y->get_w() + 10,
                y + 10));
 
        y += 50;
        add_subwindow(title = new BC_Title(x, y + 10, _("Maximum absolute offset:")));
-       add_subwindow(magnitude = new MotionMagnitude(plugin,
+       add_subwindow(magnitude = new MotionHVMagnitude(plugin,
                x + title->get_w() + 10,
                y));
 
        y += 40;
-       add_subwindow(title = new BC_Title(x, y + 10, _("Settling speed:")));
-       add_subwindow(return_speed = new MotionReturnSpeed(plugin,
+       add_subwindow(title = new BC_Title(x, y + 10, _("MotionHV settling speed:")));
+       add_subwindow(return_speed = new MotionHVReturnSpeed(plugin,
                x + title->get_w() + 10,
                y));
 
 
 
        y += 40;
-       add_subwindow(vectors = new MotionDrawVectors(plugin,
+       add_subwindow(vectors = new MotionHVDrawVectors(plugin,
                this,
                x,
                y));
@@ -258,11 +253,10 @@ void MotionWindow::create_objects()
 
 
 
-       show_window();
-       flush();
+       show_window(1);
 }
 
-void MotionWindow::update_mode()
+void MotionHVWindow::update_mode()
 {
        global_range_w->update(plugin->config.global_range_w,
                MIN_RADIUS,
@@ -274,7 +268,7 @@ void MotionWindow::update_mode()
                MIN_ROTATION,
                MAX_ROTATION);
        vectors->update(plugin->config.draw_vectors);
-       global->update(plugin->config.global);
+//     global->update(plugin->config.global);
        rotate->update(plugin->config.rotate);
 }
 
@@ -290,7 +284,7 @@ void MotionWindow::update_mode()
 
 
 
-GlobalRange::GlobalRange(MotionMain *plugin,
+GlobalRange::GlobalRange(MotionHVMain *plugin,
        int x,
        int y,
        int *value)
@@ -315,7 +309,7 @@ int GlobalRange::handle_event()
 
 
 
-RotationRange::RotationRange(MotionMain *plugin,
+RotationRange::RotationRange(MotionHVMain *plugin,
        int x,
        int y)
  : BC_IPot(x,
@@ -338,7 +332,7 @@ int RotationRange::handle_event()
 
 
 
-RotationCenter::RotationCenter(MotionMain *plugin,
+RotationCenter::RotationCenter(MotionHVMain *plugin,
        int x,
        int y)
  : BC_IPot(x,
@@ -363,7 +357,7 @@ int RotationCenter::handle_event()
 
 
 
-BlockSize::BlockSize(MotionMain *plugin,
+BlockSize::BlockSize(MotionHVMain *plugin,
        int x,
        int y,
        int *value)
@@ -397,90 +391,90 @@ int BlockSize::handle_event()
 
 
 
-GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin,
-       int x,
-       int y,
-       int w)
- : BC_PopupMenu(x,
-       y,
-       w,
-       "",
-       1)
-{
-       this->plugin = plugin;
-}
-void GlobalSearchPositions::create_objects()
-{
-       add_item(new BC_MenuItem("16"));
-       add_item(new BC_MenuItem("32"));
-       add_item(new BC_MenuItem("64"));
-       add_item(new BC_MenuItem("128"));
-       add_item(new BC_MenuItem("256"));
-       add_item(new BC_MenuItem("512"));
-       add_item(new BC_MenuItem("1024"));
-       add_item(new BC_MenuItem("2048"));
-       add_item(new BC_MenuItem("4096"));
-       add_item(new BC_MenuItem("8192"));
-       add_item(new BC_MenuItem("16384"));
-       add_item(new BC_MenuItem("32768"));
-       add_item(new BC_MenuItem("65536"));
-       add_item(new BC_MenuItem("131072"));
-       char string[BCTEXTLEN];
-       sprintf(string, "%d", plugin->config.global_positions);
-       set_text(string);
-}
-
-int GlobalSearchPositions::handle_event()
-{
-       plugin->config.global_positions = atoi(get_text());
-       plugin->send_configure_change();
-       return 1;
-}
-
-
-
-
-
-
-
-RotationSearchPositions::RotationSearchPositions(MotionMain *plugin,
-       int x,
-       int y,
-       int w)
- : BC_PopupMenu(x,
-       y,
-       w,
-       "",
-       1)
-{
-       this->plugin = plugin;
-}
-void RotationSearchPositions::create_objects()
-{
-       add_item(new BC_MenuItem("4"));
-       add_item(new BC_MenuItem("8"));
-       add_item(new BC_MenuItem("16"));
-       add_item(new BC_MenuItem("32"));
-       char string[BCTEXTLEN];
-       sprintf(string, "%d", plugin->config.rotate_positions);
-       set_text(string);
-}
-
-int RotationSearchPositions::handle_event()
-{
-       plugin->config.rotate_positions = atoi(get_text());
-       plugin->send_configure_change();
-       return 1;
-}
-
-
-
-
-
-
-
-
-MotionMagnitude::MotionMagnitude(MotionMain *plugin,
+// GlobalSearchPositions::GlobalSearchPositions(MotionHVMain *plugin,
+//     int x,
+//     int y,
+//     int w)
+//  : BC_PopupMenu(x,
+//     y,
+//     w,
+//     "",
+//     1)
+// {
+//     this->plugin = plugin;
+// }
+// void GlobalSearchPositions::create_objects()
+// {
+//     add_item(new BC_MenuItem("16"));
+//     add_item(new BC_MenuItem("32"));
+//     add_item(new BC_MenuItem("64"));
+//     add_item(new BC_MenuItem("128"));
+//     add_item(new BC_MenuItem("256"));
+//     add_item(new BC_MenuItem("512"));
+//     add_item(new BC_MenuItem("1024"));
+//     add_item(new BC_MenuItem("2048"));
+//     add_item(new BC_MenuItem("4096"));
+//     add_item(new BC_MenuItem("8192"));
+//     add_item(new BC_MenuItem("16384"));
+//     add_item(new BC_MenuItem("32768"));
+//     add_item(new BC_MenuItem("65536"));
+//     add_item(new BC_MenuItem("131072"));
+//     char string[BCTEXTLEN];
+//     sprintf(string, "%d", plugin->config.global_positions);
+//     set_text(string);
+// }
+//
+// int GlobalSearchPositions::handle_event()
+// {
+//     plugin->config.global_positions = atoi(get_text());
+//     plugin->send_configure_change();
+//     return 1;
+// }
+//
+//
+//
+//
+//
+//
+//
+// RotationSearchPositions::RotationSearchPositions(MotionHVMain *plugin,
+//     int x,
+//     int y,
+//     int w)
+//  : BC_PopupMenu(x,
+//     y,
+//     w,
+//     "",
+//     1)
+// {
+//     this->plugin = plugin;
+// }
+// void RotationSearchPositions::create_objects()
+// {
+//     add_item(new BC_MenuItem("4"));
+//     add_item(new BC_MenuItem("8"));
+//     add_item(new BC_MenuItem("16"));
+//     add_item(new BC_MenuItem("32"));
+//     char string[BCTEXTLEN];
+//     sprintf(string, "%d", plugin->config.rotate_positions);
+//     set_text(string);
+// }
+//
+// int RotationSearchPositions::handle_event()
+// {
+//     plugin->config.rotate_positions = atoi(get_text());
+//     plugin->send_configure_change();
+//     return 1;
+// }
+
+
+
+
+
+
+
+
+MotionHVMagnitude::MotionHVMagnitude(MotionHVMain *plugin,
        int x,
        int y)
  : BC_IPot(x,
@@ -492,7 +486,7 @@ MotionMagnitude::MotionMagnitude(MotionMain *plugin,
        this->plugin = plugin;
 }
 
-int MotionMagnitude::handle_event()
+int MotionHVMagnitude::handle_event()
 {
        plugin->config.magnitude = (int)get_value();
        plugin->send_configure_change();
@@ -500,7 +494,7 @@ int MotionMagnitude::handle_event()
 }
 
 
-MotionReturnSpeed::MotionReturnSpeed(MotionMain *plugin,
+MotionHVReturnSpeed::MotionHVReturnSpeed(MotionHVMain *plugin,
        int x,
        int y)
  : BC_IPot(x,
@@ -512,7 +506,7 @@ MotionReturnSpeed::MotionReturnSpeed(MotionMain *plugin,
        this->plugin = plugin;
 }
 
-int MotionReturnSpeed::handle_event()
+int MotionHVReturnSpeed::handle_event()
 {
        plugin->config.return_speed = (int)get_value();
        plugin->send_configure_change();
@@ -521,7 +515,7 @@ int MotionReturnSpeed::handle_event()
 
 
 
-MotionRMagnitude::MotionRMagnitude(MotionMain *plugin,
+MotionHVRMagnitude::MotionHVRMagnitude(MotionHVMain *plugin,
        int x,
        int y)
  : BC_IPot(x,
@@ -533,7 +527,7 @@ MotionRMagnitude::MotionRMagnitude(MotionMain *plugin,
        this->plugin = plugin;
 }
 
-int MotionRMagnitude::handle_event()
+int MotionHVRMagnitude::handle_event()
 {
        plugin->config.rotate_magnitude = (int)get_value();
        plugin->send_configure_change();
@@ -542,7 +536,7 @@ int MotionRMagnitude::handle_event()
 
 
 
-MotionRReturnSpeed::MotionRReturnSpeed(MotionMain *plugin,
+MotionHVRReturnSpeed::MotionHVRReturnSpeed(MotionHVMain *plugin,
        int x,
        int y)
  : BC_IPot(x,
@@ -554,7 +548,7 @@ MotionRReturnSpeed::MotionRReturnSpeed(MotionMain *plugin,
        this->plugin = plugin;
 }
 
-int MotionRReturnSpeed::handle_event()
+int MotionHVRReturnSpeed::handle_event()
 {
        plugin->config.rotate_return_speed = (int)get_value();
        plugin->send_configure_change();
@@ -565,28 +559,28 @@ int MotionRReturnSpeed::handle_event()
 
 
 
-MotionGlobal::MotionGlobal(MotionMain *plugin,
-       MotionWindow *gui,
-       int x,
-       int y)
- : BC_CheckBox(x,
-       y,
-       plugin->config.global,
-       _("Track translation"))
-{
-       this->plugin = plugin;
-       this->gui = gui;
-}
+// MotionHVGlobal::MotionHVGlobal(MotionHVMain *plugin,
+//     MotionHVWindow *gui,
+//     int x,
+//     int y)
+//  : BC_CheckBox(x,
+//     y,
+//     plugin->config.global,
+//     _("Track translation"))
+// {
+//     this->plugin = plugin;
+//     this->gui = gui;
+// }
+//
+// int MotionHVGlobal::handle_event()
+// {
+//     plugin->config.global = get_value();
+//     plugin->send_configure_change();
+//     return 1;
+// }
 
-int MotionGlobal::handle_event()
-{
-       plugin->config.global = get_value();
-       plugin->send_configure_change();
-       return 1;
-}
-
-MotionRotate::MotionRotate(MotionMain *plugin,
-       MotionWindow *gui,
+MotionHVRotate::MotionHVRotate(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_CheckBox(x,
@@ -598,7 +592,7 @@ MotionRotate::MotionRotate(MotionMain *plugin,
        this->gui = gui;
 }
 
-int MotionRotate::handle_event()
+int MotionHVRotate::handle_event()
 {
        plugin->config.rotate = get_value();
        plugin->send_configure_change();
@@ -609,8 +603,8 @@ int MotionRotate::handle_event()
 
 
 
-MotionBlockX::MotionBlockX(MotionMain *plugin,
-       MotionWindow *gui,
+MotionHVBlockX::MotionHVBlockX(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_FPot(x,
@@ -623,7 +617,7 @@ MotionBlockX::MotionBlockX(MotionMain *plugin,
        this->gui = gui;
 }
 
-int MotionBlockX::handle_event()
+int MotionHVBlockX::handle_event()
 {
        plugin->config.block_x = get_value();
        gui->block_x_text->update((float)plugin->config.block_x);
@@ -634,8 +628,8 @@ int MotionBlockX::handle_event()
 
 
 
-MotionBlockY::MotionBlockY(MotionMain *plugin,
-       MotionWindow *gui,
+MotionHVBlockY::MotionHVBlockY(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_FPot(x,
@@ -648,7 +642,7 @@ MotionBlockY::MotionBlockY(MotionMain *plugin,
        this->gui = gui;
 }
 
-int MotionBlockY::handle_event()
+int MotionHVBlockY::handle_event()
 {
        plugin->config.block_y = get_value();
        gui->block_y_text->update((float)plugin->config.block_y);
@@ -656,8 +650,8 @@ int MotionBlockY::handle_event()
        return 1;
 }
 
-MotionBlockXText::MotionBlockXText(MotionMain *plugin,
-       MotionWindow *gui,
+MotionHVBlockXText::MotionHVBlockXText(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_TextBox(x,
@@ -671,7 +665,7 @@ MotionBlockXText::MotionBlockXText(MotionMain *plugin,
        set_precision(4);
 }
 
-int MotionBlockXText::handle_event()
+int MotionHVBlockXText::handle_event()
 {
        plugin->config.block_x = atof(get_text());
        gui->block_x->update(plugin->config.block_x);
@@ -682,8 +676,8 @@ int MotionBlockXText::handle_event()
 
 
 
-MotionBlockYText::MotionBlockYText(MotionMain *plugin,
-       MotionWindow *gui,
+MotionHVBlockYText::MotionHVBlockYText(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_TextBox(x,
@@ -697,7 +691,7 @@ MotionBlockYText::MotionBlockYText(MotionMain *plugin,
        set_precision(4);
 }
 
-int MotionBlockYText::handle_event()
+int MotionHVBlockYText::handle_event()
 {
        plugin->config.block_y = atof(get_text());
        gui->block_y->update(plugin->config.block_y);
@@ -720,8 +714,8 @@ int MotionBlockYText::handle_event()
 
 
 
-MotionDrawVectors::MotionDrawVectors(MotionMain *plugin,
-       MotionWindow *gui,
+MotionHVDrawVectors::MotionHVDrawVectors(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_CheckBox(x,
@@ -733,7 +727,7 @@ MotionDrawVectors::MotionDrawVectors(MotionMain *plugin,
        this->plugin = plugin;
 }
 
-int MotionDrawVectors::handle_event()
+int MotionHVDrawVectors::handle_event()
 {
        plugin->config.draw_vectors = get_value();
        plugin->send_configure_change();
@@ -747,13 +741,13 @@ int MotionDrawVectors::handle_event()
 
 
 
-TrackSingleFrame::TrackSingleFrame(MotionMain *plugin,
-       MotionWindow *gui,
+TrackSingleFrame::TrackSingleFrame(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_Radial(x,
        y,
-       plugin->config.tracking_object == MotionScan::TRACK_SINGLE,
+       plugin->config.tracking_object == MotionHVScan::TRACK_SINGLE,
        _("Track single frame"))
 {
        this->plugin = plugin;
@@ -762,7 +756,7 @@ TrackSingleFrame::TrackSingleFrame(MotionMain *plugin,
 
 int TrackSingleFrame::handle_event()
 {
-       plugin->config.tracking_object = MotionScan::TRACK_SINGLE;
+       plugin->config.tracking_object = MotionHVScan::TRACK_SINGLE;
        gui->track_previous->update(0);
        gui->previous_same->update(0);
        gui->track_frame_number->enable();
@@ -777,15 +771,15 @@ int TrackSingleFrame::handle_event()
 
 
 
-TrackFrameNumber::TrackFrameNumber(MotionMain *plugin,
-       MotionWindow *gui,
+TrackFrameNumber::TrackFrameNumber(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_TextBox(x, y, 100, 1, plugin->config.track_frame)
 {
        this->plugin = plugin;
        this->gui = gui;
-       if(plugin->config.tracking_object != MotionScan::TRACK_SINGLE) disable();
+       if(plugin->config.tracking_object != MotionHVScan::TRACK_SINGLE) disable();
 }
 
 int TrackFrameNumber::handle_event()
@@ -801,13 +795,13 @@ int TrackFrameNumber::handle_event()
 
 
 
-TrackPreviousFrame::TrackPreviousFrame(MotionMain *plugin,
-       MotionWindow *gui,
+TrackPreviousFrame::TrackPreviousFrame(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_Radial(x,
        y,
-       plugin->config.tracking_object == MotionScan::TRACK_PREVIOUS,
+       plugin->config.tracking_object == MotionHVScan::TRACK_PREVIOUS,
        _("Track previous frame"))
 {
        this->plugin = plugin;
@@ -815,7 +809,7 @@ TrackPreviousFrame::TrackPreviousFrame(MotionMain *plugin,
 }
 int TrackPreviousFrame::handle_event()
 {
-       plugin->config.tracking_object = MotionScan::TRACK_PREVIOUS;
+       plugin->config.tracking_object = MotionHVScan::TRACK_PREVIOUS;
        gui->track_single->update(0);
        gui->previous_same->update(0);
        gui->track_frame_number->disable();
@@ -830,13 +824,13 @@ int TrackPreviousFrame::handle_event()
 
 
 
-PreviousFrameSameBlock::PreviousFrameSameBlock(MotionMain *plugin,
-       MotionWindow *gui,
+PreviousFrameSameBlock::PreviousFrameSameBlock(MotionHVMain *plugin,
+       MotionHVWindow *gui,
        int x,
        int y)
  : BC_Radial(x,
        y,
-       plugin->config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK,
+       plugin->config.tracking_object == MotionHVScan::PREVIOUS_SAME_BLOCK,
        _("Previous frame same block"))
 {
        this->plugin = plugin;
@@ -844,7 +838,7 @@ PreviousFrameSameBlock::PreviousFrameSameBlock(MotionMain *plugin,
 }
 int PreviousFrameSameBlock::handle_event()
 {
-       plugin->config.tracking_object = MotionScan::PREVIOUS_SAME_BLOCK;
+       plugin->config.tracking_object = MotionHVScan::PREVIOUS_SAME_BLOCK;
        gui->track_single->update(0);
        gui->track_previous->update(0);
        gui->track_frame_number->disable();
@@ -859,7 +853,7 @@ int PreviousFrameSameBlock::handle_event()
 
 
 
-MasterLayer::MasterLayer(MotionMain *plugin, MotionWindow *gui, int x, int y)
+MasterLayer::MasterLayer(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y)
  : BC_PopupMenu(x,
        y,
        calculate_w(gui),
@@ -893,7 +887,7 @@ char* MasterLayer::to_text(int mode)
        return mode ? _("Bottom") : _("Top");
 }
 
-int MasterLayer::calculate_w(MotionWindow *gui)
+int MasterLayer::calculate_w(MotionHVWindow *gui)
 {
        int result = 0;
        result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0)));
@@ -908,7 +902,7 @@ int MasterLayer::calculate_w(MotionWindow *gui)
 
 
 
-ActionType::ActionType(MotionMain *plugin, MotionWindow *gui, int x, int y)
+ActionType::ActionType(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y)
  : BC_PopupMenu(x,
        y,
        calculate_w(gui),
@@ -927,52 +921,49 @@ int ActionType::handle_event()
 
 void ActionType::create_objects()
 {
-       add_item(new BC_MenuItem(to_text(MotionScan::TRACK)));
-       add_item(new BC_MenuItem(to_text(MotionScan::TRACK_PIXEL)));
-       add_item(new BC_MenuItem(to_text(MotionScan::STABILIZE)));
-       add_item(new BC_MenuItem(to_text(MotionScan::STABILIZE_PIXEL)));
-       add_item(new BC_MenuItem(to_text(MotionScan::NOTHING)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::TRACK)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::TRACK_PIXEL)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::STABILIZE)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::STABILIZE_PIXEL)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::NOTHING)));
 }
 
 int ActionType::from_text(char *text)
 {
-       if(!strcmp(text, _("Track Subpixel"))) return MotionScan::TRACK;
-       if(!strcmp(text, _("Track Pixel"))) return MotionScan::TRACK_PIXEL;
-       if(!strcmp(text, _("Stabilize Subpixel"))) return MotionScan::STABILIZE;
-       if(!strcmp(text, _("Stabilize Pixel"))) return MotionScan::STABILIZE_PIXEL;
-       if(!strcmp(text, _("Do Nothing"))) return MotionScan::NOTHING;
+       if(!strcmp(text, _("Track Subpixel"))) return MotionHVScan::TRACK;
+       if(!strcmp(text, _("Track Pixel"))) return MotionHVScan::TRACK_PIXEL;
+       if(!strcmp(text, _("Stabilize Subpixel"))) return MotionHVScan::STABILIZE;
+       if(!strcmp(text, _("Stabilize Pixel"))) return MotionHVScan::STABILIZE_PIXEL;
+       //if(!strcmp(text, _("Do Nothing"))) return MotionHVScan::NOTHING;
+       return MotionHVScan::NOTHING;
 }
 
 char* ActionType::to_text(int mode)
 {
        switch(mode)
        {
-               case MotionScan::TRACK:
+               case MotionHVScan::TRACK:
                        return _("Track Subpixel");
-                       break;
-               case MotionScan::TRACK_PIXEL:
+               case MotionHVScan::TRACK_PIXEL:
                        return _("Track Pixel");
-                       break;
-               case MotionScan::STABILIZE:
+               case MotionHVScan::STABILIZE:
                        return _("Stabilize Subpixel");
-                       break;
-               case MotionScan::STABILIZE_PIXEL:
+               case MotionHVScan::STABILIZE_PIXEL:
                        return _("Stabilize Pixel");
-                       break;
-               case MotionScan::NOTHING:
+               default:
+               case MotionHVScan::NOTHING:
                        return _("Do Nothing");
-                       break;
        }
 }
 
-int ActionType::calculate_w(MotionWindow *gui)
+int ActionType::calculate_w(MotionHVWindow *gui)
 {
        int result = 0;
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::TRACK)));
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::TRACK_PIXEL)));
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::STABILIZE)));
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::STABILIZE_PIXEL)));
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::NOTHING)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::TRACK)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::TRACK_PIXEL)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::STABILIZE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::STABILIZE_PIXEL)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::NOTHING)));
        return result + 50;
 }
 
@@ -980,7 +971,7 @@ int ActionType::calculate_w(MotionWindow *gui)
 
 
 
-TrackingType::TrackingType(MotionMain *plugin, MotionWindow *gui, int x, int y)
+TrackingType::TrackingType(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y)
  : BC_PopupMenu(x,
        y,
        calculate_w(gui),
@@ -999,46 +990,44 @@ int TrackingType::handle_event()
 
 void TrackingType::create_objects()
 {
-       add_item(new BC_MenuItem(to_text(MotionScan::NO_CALCULATE)));
-       add_item(new BC_MenuItem(to_text(MotionScan::CALCULATE)));
-       add_item(new BC_MenuItem(to_text(MotionScan::SAVE)));
-       add_item(new BC_MenuItem(to_text(MotionScan::LOAD)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::NO_CALCULATE)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::CALCULATE)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::SAVE)));
+       add_item(new BC_MenuItem(to_text(MotionHVScan::LOAD)));
 }
 
 int TrackingType::from_text(char *text)
 {
-       if(!strcmp(text, _("Don't Calculate"))) return MotionScan::NO_CALCULATE;
-       if(!strcmp(text, _("Recalculate"))) return MotionScan::CALCULATE;
-       if(!strcmp(text, _("Save coords to /tmp"))) return MotionScan::SAVE;
-       if(!strcmp(text, _("Load coords from /tmp"))) return MotionScan::LOAD;
+       if(!strcmp(text, _("Save coords to /tmp"))) return MotionHVScan::SAVE;
+       if(!strcmp(text, _("Load coords from /tmp"))) return MotionHVScan::LOAD;
+       if(!strcmp(text, _("Recalculate"))) return MotionHVScan::CALCULATE;
+       //if(!strcmp(text, _("Don't Calculate"))) return MotionHVScan::NO_CALCULATE;
+       return MotionHVScan::NO_CALCULATE;
 }
 
 char* TrackingType::to_text(int mode)
 {
        switch(mode)
        {
-               case MotionScan::NO_CALCULATE:
-                       return _("Don't Calculate");
-                       break;
-               case MotionScan::CALCULATE:
-                       return _("Recalculate");
-                       break;
-               case MotionScan::SAVE:
+               case MotionHVScan::SAVE:
                        return _("Save coords to /tmp");
-                       break;
-               case MotionScan::LOAD:
+               case MotionHVScan::LOAD:
                        return _("Load coords from /tmp");
-                       break;
+               case MotionHVScan::CALCULATE:
+                       return _("Recalculate");
+               default:
+               case MotionHVScan::NO_CALCULATE:
+                       return _("Don't Calculate");
        }
 }
 
-int TrackingType::calculate_w(MotionWindow *gui)
+int TrackingType::calculate_w(MotionHVWindow *gui)
 {
        int result = 0;
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::NO_CALCULATE)));
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::CALCULATE)));
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::SAVE)));
-       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::LOAD)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::NO_CALCULATE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::CALCULATE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::SAVE)));
+       result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionHVScan::LOAD)));
        return result + 50;
 }
 
@@ -1051,7 +1040,7 @@ int TrackingType::calculate_w(MotionWindow *gui)
 
 
 
-TrackDirection::TrackDirection(MotionMain *plugin, MotionWindow *gui, int x, int y)
+TrackDirection::TrackDirection(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y)
  : BC_PopupMenu(x,
        y,
        calculate_w(gui),
@@ -1090,7 +1079,7 @@ char* TrackDirection::to_text(int horizontal_only, int vertical_only)
        return _("Both");
 }
 
-int TrackDirection::calculate_w(MotionWindow *gui)
+int TrackDirection::calculate_w(MotionHVWindow *gui)
 {
        int result = 0;
        result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1, 0)));
diff --git a/cinelerra-5.1/plugins/motion-hv/motionwindow-hv.h b/cinelerra-5.1/plugins/motion-hv/motionwindow-hv.h
new file mode 100644 (file)
index 0000000..220b742
--- /dev/null
@@ -0,0 +1,385 @@
+
+/*
+ * 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 "guicast.h"
+#include "motion-hv.inc"
+
+class MasterLayer : public BC_PopupMenu
+{
+public:
+       MasterLayer(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionHVWindow *gui);
+       static int from_text(char *text);
+       static char* to_text(int mode);
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class ActionType : public BC_PopupMenu
+{
+public:
+       ActionType(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionHVWindow *gui);
+       static int from_text(char *text);
+       static char* to_text(int mode);
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class TrackingType : public BC_PopupMenu
+{
+public:
+       TrackingType(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionHVWindow *gui);
+       static int from_text(char *text);
+       static char* to_text(int mode);
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class TrackDirection : public BC_PopupMenu
+{
+public:
+       TrackDirection(MotionHVMain *plugin, MotionHVWindow *gui, int x, int y);
+       int handle_event();
+       void create_objects();
+       static int calculate_w(MotionHVWindow *gui);
+       static void from_text(int *horizontal_only, int *vertical_only, char *text);
+       static char* to_text(int horizontal_only, int vertical_only);
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+
+class TrackSingleFrame : public BC_Radial
+{
+public:
+       TrackSingleFrame(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class TrackFrameNumber : public BC_TextBox
+{
+public:
+       TrackFrameNumber(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class TrackPreviousFrame : public BC_Radial
+{
+public:
+       TrackPreviousFrame(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class PreviousFrameSameBlock : public BC_Radial
+{
+public:
+       PreviousFrameSameBlock(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class GlobalRange : public BC_IPot
+{
+public:
+       GlobalRange(MotionHVMain *plugin,
+               int x,
+               int y,
+               int *value);
+       int handle_event();
+       MotionHVMain *plugin;
+       int *value;
+};
+
+class RotationRange : public BC_IPot
+{
+public:
+       RotationRange(MotionHVMain *plugin,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+};
+
+class RotationCenter : public BC_IPot
+{
+public:
+       RotationCenter(MotionHVMain *plugin,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+};
+
+class BlockSize : public BC_IPot
+{
+public:
+       BlockSize(MotionHVMain *plugin,
+               int x,
+               int y,
+               int *value);
+       int handle_event();
+       MotionHVMain *plugin;
+       int *value;
+};
+
+class MotionHVBlockX : public BC_FPot
+{
+public:
+       MotionHVBlockX(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVWindow *gui;
+       MotionHVMain *plugin;
+};
+
+class MotionHVBlockY : public BC_FPot
+{
+public:
+       MotionHVBlockY(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVWindow *gui;
+       MotionHVMain *plugin;
+};
+
+class MotionHVBlockXText : public BC_TextBox
+{
+public:
+       MotionHVBlockXText(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVWindow *gui;
+       MotionHVMain *plugin;
+};
+
+class MotionHVBlockYText : public BC_TextBox
+{
+public:
+       MotionHVBlockYText(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVWindow *gui;
+       MotionHVMain *plugin;
+};
+
+// class GlobalSearchPositions : public BC_PopupMenu
+// {
+// public:
+//     GlobalSearchPositions(MotionHVMain *plugin,
+//             int x,
+//             int y,
+//             int w);
+//     void create_objects();
+//     int handle_event();
+//     MotionHVMain *plugin;
+// };
+//
+// class RotationSearchPositions : public BC_PopupMenu
+// {
+// public:
+//     RotationSearchPositions(MotionHVMain *plugin,
+//             int x,
+//             int y,
+//             int w);
+//     void create_objects();
+//     int handle_event();
+//     MotionHVMain *plugin;
+// };
+
+class MotionHVMagnitude : public BC_IPot
+{
+public:
+       MotionHVMagnitude(MotionHVMain *plugin,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+};
+
+class MotionHVRMagnitude : public BC_IPot
+{
+public:
+       MotionHVRMagnitude(MotionHVMain *plugin,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+};
+
+class MotionHVReturnSpeed : public BC_IPot
+{
+public:
+       MotionHVReturnSpeed(MotionHVMain *plugin,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+};
+
+
+class MotionHVRReturnSpeed : public BC_IPot
+{
+public:
+       MotionHVRReturnSpeed(MotionHVMain *plugin,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+};
+
+
+class MotionHVDrawVectors : public BC_CheckBox
+{
+public:
+       MotionHVDrawVectors(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVMain *plugin;
+       MotionHVWindow *gui;
+};
+
+class AddTrackedFrameOffset : public BC_CheckBox
+{
+public:
+       AddTrackedFrameOffset(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVWindow *gui;
+       MotionHVMain *plugin;
+};
+
+// class MotionHVGlobal : public BC_CheckBox
+// {
+// public:
+//     MotionHVGlobal(MotionHVMain *plugin,
+//             MotionHVWindow *gui,
+//             int x,
+//             int y);
+//     int handle_event();
+//     MotionHVWindow *gui;
+//     MotionHVMain *plugin;
+// };
+
+class MotionHVRotate : public BC_CheckBox
+{
+public:
+       MotionHVRotate(MotionHVMain *plugin,
+               MotionHVWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       MotionHVWindow *gui;
+       MotionHVMain *plugin;
+};
+
+
+
+class MotionHVWindow : public PluginClientWindow
+{
+public:
+       MotionHVWindow(MotionHVMain *plugin);
+       ~MotionHVWindow();
+
+       void create_objects();
+       void update_mode();
+       char* get_radius_title();
+
+       GlobalRange *global_range_w;
+       GlobalRange *global_range_h;
+       RotationRange *rotation_range;
+       RotationCenter *rotation_center;
+       BlockSize *global_block_w;
+       BlockSize *global_block_h;
+       BlockSize *rotation_block_w;
+       BlockSize *rotation_block_h;
+       MotionHVBlockX *block_x;
+       MotionHVBlockY *block_y;
+       MotionHVBlockXText *block_x_text;
+       MotionHVBlockYText *block_y_text;
+//     GlobalSearchPositions *global_search_positions;
+//     RotationSearchPositions *rotation_search_positions;
+       MotionHVMagnitude *magnitude;
+       MotionHVRMagnitude *rotate_magnitude;
+       MotionHVReturnSpeed *return_speed;
+       MotionHVRReturnSpeed *rotate_return_speed;
+       ActionType *action_type;
+       MotionHVDrawVectors *vectors;
+//     MotionHVGlobal *global;
+       MotionHVRotate *rotate;
+       AddTrackedFrameOffset *addtrackedframeoffset;
+       TrackSingleFrame *track_single;
+       TrackFrameNumber *track_frame_number;
+       TrackPreviousFrame *track_previous;
+       PreviousFrameSameBlock *previous_same;
+       MasterLayer *master_layer;
+       TrackingType *tracking_type;
+       TrackDirection *track_direction;
+
+       MotionHVMain *plugin;
+};
+
+
+
+
+
+
+
+
+
similarity index 89%
rename from cinelerra-5.1/plugins/motion.new/motionwindow.inc
rename to cinelerra-5.1/plugins/motion-hv/motionwindow-hv.inc
index 8fbef4672d9b8bf70bfc82ff079451253a0643b3..160075ba6e0634a5eb3b106a79476584c91c5382 100644 (file)
  *
  */
 
-#ifndef MOTIONWINDOW_INC
-#define MOTIONWINDOW_INC
+#ifndef MOTIONWINDOWHV_INC
+#define MOTIONWINDOWHV_INC
 
-class MotionWindow;
-class MotionThread;
+class MotionHVWindow;
+class MotionHVThread;
 
 #endif
diff --git a/cinelerra-5.1/plugins/motion-hv/picon.png b/cinelerra-5.1/plugins/motion-hv/picon.png
new file mode 100644 (file)
index 0000000..01b282a
Binary files /dev/null and b/cinelerra-5.1/plugins/motion-hv/picon.png differ
diff --git a/cinelerra-5.1/plugins/motion-hv/theme_suv.png b/cinelerra-5.1/plugins/motion-hv/theme_suv.png
new file mode 100644 (file)
index 0000000..e281613
Binary files /dev/null and b/cinelerra-5.1/plugins/motion-hv/theme_suv.png differ
diff --git a/cinelerra-5.1/plugins/motion.new/Makefile b/cinelerra-5.1/plugins/motion.new/Makefile
deleted file mode 100644 (file)
index 93ba09b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-include ../../plugin_defs
-
-OBJS := \
-       $(OBJDIR)/motion.o \
-       $(OBJDIR)/motionscan.o \
-       $(OBJDIR)/motionwindow.o
-
-PLUGIN = motion
-
-include ../../plugin_config
-
-$(OBJDIR)/motion.o: motion.C
-$(OBJDIR)/motionscan.o: motionscan.C
-$(OBJDIR)/motionwindow.o: motionwindow.C
diff --git a/cinelerra-5.1/plugins/motion.new/motionscan.C b/cinelerra-5.1/plugins/motion.new/motionscan.C
deleted file mode 100644 (file)
index a04b9b4..0000000
+++ /dev/null
@@ -1,1090 +0,0 @@
-
-/*
- * 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 "clip.h"
-//#include "../downsample/downsampleengine.h"
-//#include "motion.h"
-#include "motionscan.h"
-#include "mutex.h"
-#include "vframe.h"
-
-#include <math.h>
-
-// The module which does the actual scanning
-
-MotionScanPackage::MotionScanPackage()
- : LoadPackage()
-{
-       valid = 1;
-}
-
-
-
-
-
-
-MotionScanUnit::MotionScanUnit(MotionScan *server)
- : LoadClient(server)
-{
-       this->server = server;
-       cache_lock = new Mutex("MotionScanUnit::cache_lock");
-}
-
-MotionScanUnit::~MotionScanUnit()
-{
-       delete cache_lock;
-}
-
-
-
-void MotionScanUnit::process_package(LoadPackage *package)
-{
-       MotionScanPackage *pkg = (MotionScanPackage*)package;
-       int w = server->current_frame->get_w();
-       int h = server->current_frame->get_h();
-       int color_model = server->current_frame->get_color_model();
-       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
-       int row_bytes = server->current_frame->get_bytes_per_line();
-
-
-
-
-
-
-
-
-
-
-
-
-// Single pixel
-       if(!server->subpixel)
-       {
-// Try cache
-               pkg->difference1 = server->get_cache(pkg->search_x, pkg->search_y);
-               if(pkg->difference1 < 0)
-               {
-//printf("MotionScanUnit::process_package 1 search_x=%d search_y=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n",
-//pkg->search_x, pkg->search_y, pkg->scan_x1, pkg->scan_y1, pkg->scan_x2, pkg->scan_y2, server->x_steps, server->y_steps);
-// Pointers to first pixel in each block
-                       unsigned char *prev_ptr = server->previous_frame->get_rows()[
-                               pkg->search_y] +
-                               pkg->search_x * pixel_size;
-                       unsigned char *current_ptr = server->current_frame->get_rows()[
-                               pkg->block_y1] +
-                               pkg->block_x1 * pixel_size;
-
-// Scan block
-                       pkg->difference1 = MotionScan::abs_diff(prev_ptr,
-                               current_ptr,
-                               row_bytes,
-                               pkg->block_x2 - pkg->block_x1,
-                               pkg->block_y2 - pkg->block_y1,
-                               color_model);
-
-// printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n",
-// __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
-                       server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1);
-               }
-       }
-
-
-
-
-
-
-
-       else
-
-
-
-
-
-
-
-
-// Sub pixel
-       {
-               unsigned char *prev_ptr = server->previous_frame->get_rows()[
-                       pkg->search_y] +
-                       pkg->search_x * pixel_size;
-               unsigned char *current_ptr = server->current_frame->get_rows()[
-                       pkg->block_y1] +
-                       pkg->block_x1 * pixel_size;
-
-// With subpixel, there are two ways to compare each position, one by shifting
-// the previous frame and two by shifting the current frame.
-               pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr,
-                       current_ptr,
-                       row_bytes,
-                       pkg->block_x2 - pkg->block_x1,
-                       pkg->block_y2 - pkg->block_y1,
-                       color_model,
-                       pkg->sub_x,
-                       pkg->sub_y);
-               pkg->difference2 = MotionScan::abs_diff_sub(current_ptr,
-                       prev_ptr,
-                       row_bytes,
-                       pkg->block_x2 - pkg->block_x1,
-                       pkg->block_y2 - pkg->block_y1,
-                       color_model,
-                       pkg->sub_x,
-                       pkg->sub_y);
-// printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
-// sub_x,
-// sub_y,
-// search_x,
-// search_y,
-// pkg->difference1,
-// pkg->difference2);
-       }
-
-
-
-
-}
-
-
-
-
-
-
-
-
-
-
-int64_t MotionScanUnit::get_cache(int x, int y)
-{
-       int64_t result = -1;
-       cache_lock->lock("MotionScanUnit::get_cache");
-       for(int i = 0; i < cache.total; i++)
-       {
-               MotionScanCache *ptr = cache.values[i];
-               if(ptr->x == x && ptr->y == y)
-               {
-                       result = ptr->difference;
-                       break;
-               }
-       }
-       cache_lock->unlock();
-       return result;
-}
-
-void MotionScanUnit::put_cache(int x, int y, int64_t difference)
-{
-       MotionScanCache *ptr = new MotionScanCache(x, y, difference);
-       cache_lock->lock("MotionScanUnit::put_cache");
-       cache.append(ptr);
-       cache_lock->unlock();
-}
-
-
-
-
-
-
-
-
-
-
-
-MotionScan::MotionScan(int total_clients,
-       int total_packages)
- : LoadServer(
-//1, 1
-total_clients, total_packages
-)
-{
-       test_match = 1;
-       cache_lock = new Mutex("MotionScan::cache_lock");
-       downsampled_previous = 0;
-       downsampled_current = 0;
-//     downsample = 0;
-}
-
-MotionScan::~MotionScan()
-{
-       delete cache_lock;
-       delete downsampled_previous;
-       delete downsampled_current;
-//     delete downsample;
-}
-
-
-void MotionScan::init_packages()
-{
-// Set package coords
-//printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages());
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-
-               pkg->block_x1 = block_x1;
-               pkg->block_x2 = block_x2;
-               pkg->block_y1 = block_y1;
-               pkg->block_y2 = block_y2;
-               pkg->scan_x1 = scan_x1;
-               pkg->scan_x2 = scan_x2;
-               pkg->scan_y1 = scan_y1;
-               pkg->scan_y2 = scan_y2;
-               pkg->step = i;
-               pkg->difference1 = 0;
-               pkg->difference2 = 0;
-               pkg->dx = 0;
-               pkg->dy = 0;
-               pkg->valid = 1;
-
-               if(!subpixel)
-               {
-                       pkg->search_x = pkg->scan_x1 + (pkg->step % x_steps) *
-                               (scan_x2 - scan_x1) / x_steps;
-                       pkg->search_y = pkg->scan_y1 + (pkg->step / x_steps) *
-                               (scan_y2 - scan_y1) / y_steps;
-                       pkg->sub_x = 0;
-                       pkg->sub_y = 0;
-               }
-               else
-               {
-                       pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
-                       pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
-
-                       if(horizontal_only)
-                       {
-                               pkg->sub_y = 0;
-                       }
-
-                       if(vertical_only)
-                       {
-                               pkg->sub_x = 0;
-                       }
-
-                       pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
-                       pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
-                       pkg->sub_x %= OVERSAMPLE;
-                       pkg->sub_y %= OVERSAMPLE;
-
-
-
-// printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n",
-// __LINE__,
-// i,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->sub_x,
-// pkg->sub_y);
-               }
-
-// printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
-// __LINE__,
-// scan_x1,
-// scan_x2,
-// scan_y1,
-// scan_y2,
-// pkg->search_x,
-// pkg->search_y);
-       }
-}
-
-LoadClient* MotionScan::new_client()
-{
-       return new MotionScanUnit(this);
-}
-
-LoadPackage* MotionScan::new_package()
-{
-       return new MotionScanPackage;
-}
-
-
-void MotionScan::set_test_match(int value)
-{
-       this->test_match = value;
-}
-
-void MotionScan::scan_frame(VFrame *previous_frame,
-       VFrame *current_frame,
-       int global_range_w,
-       int global_range_h,
-       int global_block_w,
-       int global_block_h,
-       double block_x,
-       double block_y,
-       int frame_type,
-       int tracking_type,
-       int action_type,
-       int horizontal_only,
-       int vertical_only,
-       int source_position,
-       int total_steps,
-       int total_dx,
-       int total_dy,
-       int global_origin_x,
-       int global_origin_y)
-{
-       this->previous_frame_arg = previous_frame;
-       this->current_frame_arg = current_frame;
-       this->horizontal_only = horizontal_only;
-       this->vertical_only = vertical_only;
-       this->previous_frame = previous_frame_arg;
-       this->current_frame = current_frame_arg;
-       this->global_origin_x = global_origin_x;
-       this->global_origin_y = global_origin_y;
-       subpixel = 0;
-
-       cache.remove_all_objects();
-
-// Single macroblock
-       int w = current_frame->get_w();
-       int h = current_frame->get_h();
-
-// Initial search parameters
-       int scan_w = w * global_range_w / 100;
-       int scan_h = h * global_range_h / 100;
-       int block_w = w * global_block_w / 100;
-       int block_h = h * global_block_h / 100;
-
-// Location of block in previous frame
-       block_x1 = (int)(w * block_x / 100 - block_w / 2);
-       block_y1 = (int)(h * block_y / 100 - block_h / 2);
-       block_x2 = (int)(w * block_x / 100 + block_w / 2);
-       block_y2 = (int)(h * block_y / 100 + block_h / 2);
-
-// Offset to location of previous block.  This offset needn't be very accurate
-// since it's the offset of the previous image and current image we want.
-       if(frame_type == MotionScan::TRACK_PREVIOUS)
-       {
-               block_x1 += total_dx / OVERSAMPLE;
-               block_y1 += total_dy / OVERSAMPLE;
-               block_x2 += total_dx / OVERSAMPLE;
-               block_y2 += total_dy / OVERSAMPLE;
-       }
-
-       skip = 0;
-
-       switch(tracking_type)
-       {
-// Don't calculate
-               case MotionScan::NO_CALCULATE:
-                       dx_result = 0;
-                       dy_result = 0;
-                       skip = 1;
-                       break;
-
-               case MotionScan::LOAD:
-               {
-//printf("MotionScan::scan_frame %d\n", __LINE__);
-// Load result from disk
-                       char string[BCTEXTLEN];
-                       sprintf(string, "%s%06d",
-                               MOTION_FILE,
-                               source_position);
-                       FILE *input = fopen(string, "r");
-                       if(input)
-                       {
-                               fscanf(input,
-                                       "%d %d",
-                                       &dx_result,
-                                       &dy_result);
-                               fclose(input);
-                               skip = 1;
-                       }
-                       break;
-               }
-
-// Scan from scratch
-               default:
-                       skip = 0;
-                       break;
-       }
-
-       if(!skip && test_match)
-       {
-               if(previous_frame->data_matches(current_frame))
-               {
-printf("MotionScan::scan_frame: data matches. skipping.\n");
-                       dx_result = 0;
-                       dy_result = 0;
-                       skip = 1;
-               }
-       }
-
-// Perform scan
-       if(!skip)
-       {
-//printf("MotionScan::scan_frame %d\n", __LINE__);
-// Location of block in current frame
-               int origin_offset_x = this->global_origin_x * w / 100;
-               int origin_offset_y = this->global_origin_y * h / 100;
-               int x_result = block_x1 + origin_offset_x;
-               int y_result = block_y1 + origin_offset_y;
-
-// printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
-// block_x1 + block_w / 2,
-// block_y1 + block_h / 2,
-// block_w,
-// block_h,
-// block_x1,
-// block_y1,
-// block_x2,
-// block_y2);
-
-               while(1)
-               {
-// Cache needs to be cleared if downsampling is used because the sums of
-// different downsamplings can't be compared.
-// Subpixel never uses the cache.
-//                     cache.remove_all_objects();
-                       scan_x1 = x_result - scan_w / 2;
-                       scan_y1 = y_result - scan_h / 2;
-                       scan_x2 = x_result + scan_w / 2;
-                       scan_y2 = y_result + scan_h / 2;
-
-
-
-// Zero out requested values
-                       if(horizontal_only)
-                       {
-                               scan_y1 = block_y1;
-                               scan_y2 = block_y1 + 1;
-                       }
-                       if(vertical_only)
-                       {
-                               scan_x1 = block_x1;
-                               scan_x2 = block_x1 + 1;
-                       }
-
-// printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
-// block_x1,
-// block_y1,
-// block_x2,
-// block_y2,
-// scan_x1,
-// scan_y1,
-// scan_x2,
-// scan_y2);
-// Clamp the block coords before the scan so we get useful scan coords.
-                       clamp_scan(w,
-                               h,
-                               &block_x1,
-                               &block_y1,
-                               &block_x2,
-                               &block_y2,
-                               &scan_x1,
-                               &scan_y1,
-                               &scan_x2,
-                               &scan_y2,
-                               0);
-// printf("MotionScan::scan_frame 1 %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n        scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n    x_result=%d y_result=%d\n",
-// __LINE__,
-// block_x1,
-// block_y1,
-// block_x2,
-// block_y2,
-// scan_x1,
-// scan_y1,
-// scan_x2,
-// scan_y2,
-// x_result,
-// y_result);
-
-
-// Give up if invalid coords.
-                       if(scan_y2 <= scan_y1 ||
-                               scan_x2 <= scan_x1 ||
-                               block_x2 <= block_x1 ||
-                               block_y2 <= block_y1)
-                               break;
-
-// For subpixel, the top row and left column are skipped
-                       if(subpixel)
-                       {
-
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
-// Scan every subpixel in a 2 pixel * 2 pixel square
-                               total_pixels = (2 * OVERSAMPLE) * (2 * OVERSAMPLE);
-
-                               this->total_steps = total_pixels;
-// These aren't used in subpixel
-                               this->x_steps = OVERSAMPLE * 2;
-                               this->y_steps = OVERSAMPLE * 2;
-
-                               set_package_count(this->total_steps);
-                               process_packages();
-
-// Get least difference
-                               int64_t min_difference = -1;
-                               for(int i = 0; i < get_total_packages(); i++)
-                               {
-                                       MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-//printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
-//__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
-                                       if(pkg->difference1 < min_difference || min_difference == -1)
-                                       {
-                                               min_difference = pkg->difference1;
-
-// The sub coords are 1 pixel up & left of the block coords
-                                               x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
-                                               y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
-
-
-// Fill in results
-                                               dx_result = block_x1 * OVERSAMPLE - x_result;
-                                               dy_result = block_y1 * OVERSAMPLE - y_result;
-//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
-//__LINE__, dx_result, dy_result, min_difference);
-                                       }
-
-                                       if(pkg->difference2 < min_difference)
-                                       {
-                                               min_difference = pkg->difference2;
-
-                                               x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x;
-                                               y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y;
-
-                                               dx_result = block_x1 * OVERSAMPLE - x_result;
-                                               dy_result = block_y1 * OVERSAMPLE - y_result;
-//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
-//__LINE__, dx_result, dy_result, min_difference);
-                                       }
-                               }
-
-                               break;
-                       }
-                       else
-// Single pixel
-                       {
-                               total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
-                               this->total_steps = MIN(total_steps, total_pixels);
-
-                               if(this->total_steps == total_pixels)
-                               {
-                                       x_steps = scan_x2 - scan_x1;
-                                       y_steps = scan_y2 - scan_y1;
-                               }
-                               else
-                               {
-                                       x_steps = (int)sqrt(this->total_steps);
-                                       y_steps = (int)sqrt(this->total_steps);
-                               }
-
-// Use downsampled images
-//                             if(scan_x2 - scan_x1 > x_steps * 4 ||
-//                                     scan_y2 - scan_y1 > y_steps * 4)
-//                             {
-// printf("MotionScan::scan_frame %d total_pixels=%d total_steps=%d x_steps=%d y_steps=%d x y steps=%d\n",
-// __LINE__,
-// total_pixels,
-// total_steps,
-// x_steps,
-// y_steps,
-// x_steps * y_steps);
-//
-//                                     if(!downsampled_previous ||
-//                                             !downsampled_previous->equivalent(previous_frame_arg))
-//                                     {
-//                                             delete downsampled_previous;
-//                                             downsampled_previous = new VFrame(*previous_frame_arg);
-//                                     }
-//
-//                                     if(!downsampled_current ||
-//                                             !downsampled_current->equivalent(current_frame_arg))
-//                                     {
-//                                             delete downsampled_current;
-//                                             downsampled_current = new VFrame(*current_frame_arg);
-//                                     }
-//
-//
-//                                     if(!downsample)
-//                                             downsample = new DownSampleServer(get_total_clients(),
-//                                                     get_total_clients());
-//                                     downsample->process_frame(downsampled_previous,
-//                                             previous_frame_arg,
-//                                             1,
-//                                             1,
-//                                             1,
-//                                             1,
-//                                             (scan_y2 - scan_y1) / y_steps,
-//                                             (scan_x2 - scan_x1) / x_steps,
-//                                             0,
-//                                             0);
-//                                     downsample->process_frame(downsampled_current,
-//                                             current_frame_arg,
-//                                             1,
-//                                             1,
-//                                             1,
-//                                             1,
-//                                             (scan_y2 - scan_y1) / y_steps,
-//                                             (scan_x2 - scan_x1) / x_steps,
-//                                             0,
-//                                             0);
-//                                     this->previous_frame = downsampled_previous;
-//                                     this->current_frame = downsampled_current;
-//                             }
-
-
-
-
-
-// printf("MotionScan::scan_frame %d this->total_steps=%d\n",
-// __LINE__,
-// this->total_steps);
-
-
-                               set_package_count(this->total_steps);
-                               process_packages();
-
-// Get least difference
-                               int64_t min_difference = -1;
-                               for(int i = 0; i < get_total_packages(); i++)
-                               {
-                                       MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-//printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
-//__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
-                                       if(pkg->difference1 < min_difference || min_difference == -1)
-                                       {
-                                               min_difference = pkg->difference1;
-                                               x_result = pkg->search_x;
-                                               y_result = pkg->search_y;
-                                               x_result *= OVERSAMPLE;
-                                               y_result *= OVERSAMPLE;
-//printf("MotionScan::scan_frame %d x_result=%d y_result=%d diff=%lld\n",
-//__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, pkg->difference1);
-                                       }
-                               }
-
-
-// If a new search is required, rescale results back to pixels.
-                               if(this->total_steps >= total_pixels)
-                               {
-// Single pixel accuracy reached.  Now do exhaustive subpixel search.
-                                       if(action_type == MotionScan::STABILIZE ||
-                                               action_type == MotionScan::TRACK ||
-                                               action_type == MotionScan::NOTHING)
-                                       {
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
-                                               x_result /= OVERSAMPLE;
-                                               y_result /= OVERSAMPLE;
-                                               scan_w = 2;
-                                               scan_h = 2;
-                                               subpixel = 1;
-                                       }
-                                       else
-                                       {
-// Fill in results and quit
-                                               dx_result = block_x1 * OVERSAMPLE - x_result;
-                                               dy_result = block_y1 * OVERSAMPLE - y_result;
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
-                                               break;
-                                       }
-                               }
-                               else
-// Reduce scan area and try again
-                               {
-                                       scan_w = (scan_x2 - scan_x1) / 2;
-                                       scan_h = (scan_y2 - scan_y1) / 2;
-                                       x_result /= OVERSAMPLE;
-                                       y_result /= OVERSAMPLE;
-                               }
-                       }
-               }
-
-               dx_result *= -1;
-               dy_result *= -1;
-       }
-//printf("MotionScan::scan_frame %d\n", __LINE__);
-
-
-       if(vertical_only) dx_result = 0;
-       if(horizontal_only) dy_result = 0;
-
-
-
-// Write results
-       if(tracking_type == MotionScan::SAVE)
-       {
-               char string[BCTEXTLEN];
-               sprintf(string,
-                       "%s%06d",
-                       MOTION_FILE,
-                       source_position);
-               FILE *output = fopen(string, "w");
-               if(output)
-               {
-                       fprintf(output,
-                               "%d %d\n",
-                               dx_result,
-                               dy_result);
-                       fclose(output);
-               }
-               else
-               {
-                       printf("MotionScan::scan_frame %d: save coordinate failed", __LINE__);
-               }
-       }
-
-// printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n",
-// __LINE__,
-// (float)this->dx_result / OVERSAMPLE,
-// (float)this->dy_result / OVERSAMPLE);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-int64_t MotionScan::get_cache(int x, int y)
-{
-       int64_t result = -1;
-       cache_lock->lock("MotionScan::get_cache");
-       for(int i = 0; i < cache.total; i++)
-       {
-               MotionScanCache *ptr = cache.values[i];
-               if(ptr->x == x && ptr->y == y)
-               {
-                       result = ptr->difference;
-                       break;
-               }
-       }
-       cache_lock->unlock();
-       return result;
-}
-
-void MotionScan::put_cache(int x, int y, int64_t difference)
-{
-       MotionScanCache *ptr = new MotionScanCache(x, y, difference);
-       cache_lock->lock("MotionScan::put_cache");
-       cache.append(ptr);
-       cache_lock->unlock();
-}
-
-
-
-#define ABS_DIFF(type, temp_type, multiplier, components) \
-{ \
-       temp_type result_temp = 0; \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *prev_row = (type*)prev_ptr; \
-               type *current_row = (type*)current_ptr; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               temp_type difference; \
-                               difference = *prev_row++ - *current_row++; \
-                               if(difference < 0) \
-                                       result_temp -= difference; \
-                               else \
-                                       result_temp += difference; \
-                       } \
-                       if(components == 4) \
-                       { \
-                               prev_row++; \
-                               current_row++; \
-                       } \
-               } \
-               prev_ptr += row_bytes; \
-               current_ptr += row_bytes; \
-       } \
-       result = (int64_t)(result_temp * multiplier); \
-}
-
-int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
-       unsigned char *current_ptr,
-       int row_bytes,
-       int w,
-       int h,
-       int color_model)
-{
-       int64_t result = 0;
-       switch(color_model)
-       {
-               case BC_RGB888:
-                       ABS_DIFF(unsigned char, int64_t, 1, 3)
-                       break;
-               case BC_RGBA8888:
-                       ABS_DIFF(unsigned char, int64_t, 1, 4)
-                       break;
-               case BC_RGB_FLOAT:
-                       ABS_DIFF(float, double, 0x10000, 3)
-                       break;
-               case BC_RGBA_FLOAT:
-                       ABS_DIFF(float, double, 0x10000, 4)
-                       break;
-               case BC_YUV888:
-                       ABS_DIFF(unsigned char, int64_t, 1, 3)
-                       break;
-               case BC_YUVA8888:
-                       ABS_DIFF(unsigned char, int64_t, 1, 4)
-                       break;
-               case BC_YUV161616:
-                       ABS_DIFF(uint16_t, int64_t, 1, 3)
-                       break;
-               case BC_YUVA16161616:
-                       ABS_DIFF(uint16_t, int64_t, 1, 4)
-                       break;
-       }
-       return result;
-}
-
-
-
-#define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
-{ \
-       temp_type result_temp = 0; \
-       temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
-       temp_type y1_fraction = 0x100 - y2_fraction; \
-       temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
-       temp_type x1_fraction = 0x100 - x2_fraction; \
-       for(int i = 0; i < h_sub; i++) \
-       { \
-               type *prev_row1 = (type*)prev_ptr; \
-               type *prev_row2 = (type*)prev_ptr + components; \
-               type *prev_row3 = (type*)(prev_ptr + row_bytes); \
-               type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
-               type *current_row = (type*)current_ptr; \
-               for(int j = 0; j < w_sub; j++) \
-               { \
-/* Scan each component */ \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               temp_type difference; \
-                               temp_type prev_value = \
-                                       (*prev_row1++ * x1_fraction * y1_fraction + \
-                                       *prev_row2++ * x2_fraction * y1_fraction + \
-                                       *prev_row3++ * x1_fraction * y2_fraction + \
-                                       *prev_row4++ * x2_fraction * y2_fraction) / \
-                                       0x100 / 0x100; \
-                               temp_type current_value = *current_row++; \
-                               difference = prev_value - current_value; \
-                               if(difference < 0) \
-                                       result_temp -= difference; \
-                               else \
-                                       result_temp += difference; \
-                       } \
- \
-/* skip alpha */ \
-                       if(components == 4) \
-                       { \
-                               prev_row1++; \
-                               prev_row2++; \
-                               prev_row3++; \
-                               prev_row4++; \
-                               current_row++; \
-                       } \
-               } \
-               prev_ptr += row_bytes; \
-               current_ptr += row_bytes; \
-       } \
-       result = (int64_t)(result_temp * multiplier); \
-}
-
-
-
-
-int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
-       unsigned char *current_ptr,
-       int row_bytes,
-       int w,
-       int h,
-       int color_model,
-       int sub_x,
-       int sub_y)
-{
-       int h_sub = h - 1;
-       int w_sub = w - 1;
-       int64_t result = 0;
-
-       switch(color_model)
-       {
-               case BC_RGB888:
-                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
-                       break;
-               case BC_RGBA8888:
-                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
-                       break;
-               case BC_RGB_FLOAT:
-                       ABS_DIFF_SUB(float, double, 0x10000, 3)
-                       break;
-               case BC_RGBA_FLOAT:
-                       ABS_DIFF_SUB(float, double, 0x10000, 4)
-                       break;
-               case BC_YUV888:
-                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
-                       break;
-               case BC_YUVA8888:
-                       ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
-                       break;
-               case BC_YUV161616:
-                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
-                       break;
-               case BC_YUVA16161616:
-                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
-                       break;
-       }
-       return result;
-}
-
-
-
-
-
-MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
-{
-       this->x = x;
-       this->y = y;
-       this->difference = difference;
-}
-
-
-
-void MotionScan::clamp_scan(int w,
-       int h,
-       int *block_x1,
-       int *block_y1,
-       int *block_x2,
-       int *block_y2,
-       int *scan_x1,
-       int *scan_y1,
-       int *scan_x2,
-       int *scan_y2,
-       int use_absolute)
-{
-// printf("MotionMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
-// w,
-// h,
-// *block_x1,
-// *block_y1,
-// *block_x2,
-// *block_y2,
-// *scan_x1,
-// *scan_y1,
-// *scan_x2,
-// *scan_y2,
-// use_absolute);
-
-       if(use_absolute)
-       {
-// scan is always out of range before block.
-               if(*scan_x1 < 0)
-               {
-                       int difference = -*scan_x1;
-                       *block_x1 += difference;
-                       *scan_x1 = 0;
-               }
-
-               if(*scan_y1 < 0)
-               {
-                       int difference = -*scan_y1;
-                       *block_y1 += difference;
-                       *scan_y1 = 0;
-               }
-
-               if(*scan_x2 > w)
-               {
-                       int difference = *scan_x2 - w;
-                       *block_x2 -= difference;
-                       *scan_x2 -= difference;
-               }
-
-               if(*scan_y2 > h)
-               {
-                       int difference = *scan_y2 - h;
-                       *block_y2 -= difference;
-                       *scan_y2 -= difference;
-               }
-
-               CLAMP(*scan_x1, 0, w);
-               CLAMP(*scan_y1, 0, h);
-               CLAMP(*scan_x2, 0, w);
-               CLAMP(*scan_y2, 0, h);
-       }
-       else
-       {
-               if(*scan_x1 < 0)
-               {
-                       int difference = -*scan_x1;
-                       *block_x1 += difference;
-                       *scan_x2 += difference;
-                       *scan_x1 = 0;
-               }
-
-               if(*scan_y1 < 0)
-               {
-                       int difference = -*scan_y1;
-                       *block_y1 += difference;
-                       *scan_y2 += difference;
-                       *scan_y1 = 0;
-               }
-
-               if(*scan_x2 - *block_x1 + *block_x2 > w)
-               {
-                       int difference = *scan_x2 - *block_x1 + *block_x2 - w;
-                       *block_x2 -= difference;
-               }
-
-               if(*scan_y2 - *block_y1 + *block_y2 > h)
-               {
-                       int difference = *scan_y2 - *block_y1 + *block_y2 - h;
-                       *block_y2 -= difference;
-               }
-
-//             CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
-//             CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
-//             CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
-//             CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
-       }
-
-// Sanity checks which break the calculation but should never happen if the
-// center of the block is inside the frame.
-       CLAMP(*block_x1, 0, w);
-       CLAMP(*block_x2, 0, w);
-       CLAMP(*block_y1, 0, h);
-       CLAMP(*block_y2, 0, h);
-
-// printf("MotionMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
-// w,
-// h,
-// *block_x1,
-// *block_y1,
-// *block_x2,
-// *block_y2,
-// *scan_x1,
-// *scan_y1,
-// *scan_x2,
-// *scan_y2,
-// use_absolute);
-}
-
-
-
diff --git a/cinelerra-5.1/plugins/motion.new/motionwindow.h b/cinelerra-5.1/plugins/motion.new/motionwindow.h
deleted file mode 100644 (file)
index 02aa13b..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-
-/*
- * 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 "guicast.h"
-#include "motion.inc"
-
-class MasterLayer : public BC_PopupMenu
-{
-public:
-       MasterLayer(MotionMain *plugin, MotionWindow *gui, int x, int y);
-       int handle_event();
-       void create_objects();
-       static int calculate_w(MotionWindow *gui);
-       static int from_text(char *text);
-       static char* to_text(int mode);
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-class ActionType : public BC_PopupMenu
-{
-public:
-       ActionType(MotionMain *plugin, MotionWindow *gui, int x, int y);
-       int handle_event();
-       void create_objects();
-       static int calculate_w(MotionWindow *gui);
-       static int from_text(char *text);
-       static char* to_text(int mode);
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-class TrackingType : public BC_PopupMenu
-{
-public:
-       TrackingType(MotionMain *plugin, MotionWindow *gui, int x, int y);
-       int handle_event();
-       void create_objects();
-       static int calculate_w(MotionWindow *gui);
-       static int from_text(char *text);
-       static char* to_text(int mode);
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-class TrackDirection : public BC_PopupMenu
-{
-public:
-       TrackDirection(MotionMain *plugin, MotionWindow *gui, int x, int y);
-       int handle_event();
-       void create_objects();
-       static int calculate_w(MotionWindow *gui);
-       static void from_text(int *horizontal_only, int *vertical_only, char *text);
-       static char* to_text(int horizontal_only, int vertical_only);
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-
-class TrackSingleFrame : public BC_Radial
-{
-public:
-       TrackSingleFrame(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-class TrackFrameNumber : public BC_TextBox
-{
-public:
-       TrackFrameNumber(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-class TrackPreviousFrame : public BC_Radial
-{
-public:
-       TrackPreviousFrame(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-class PreviousFrameSameBlock : public BC_Radial
-{
-public:
-       PreviousFrameSameBlock(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-class GlobalRange : public BC_IPot
-{
-public:
-       GlobalRange(MotionMain *plugin,
-               int x,
-               int y,
-               int *value);
-       int handle_event();
-       MotionMain *plugin;
-       int *value;
-};
-
-class RotationRange : public BC_IPot
-{
-public:
-       RotationRange(MotionMain *plugin,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-};
-
-class RotationCenter : public BC_IPot
-{
-public:
-       RotationCenter(MotionMain *plugin,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-};
-
-class BlockSize : public BC_IPot
-{
-public:
-       BlockSize(MotionMain *plugin,
-               int x,
-               int y,
-               int *value);
-       int handle_event();
-       MotionMain *plugin;
-       int *value;
-};
-
-class MotionBlockX : public BC_FPot
-{
-public:
-       MotionBlockX(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionWindow *gui;
-       MotionMain *plugin;
-};
-
-class MotionBlockY : public BC_FPot
-{
-public:
-       MotionBlockY(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionWindow *gui;
-       MotionMain *plugin;
-};
-
-class MotionBlockXText : public BC_TextBox
-{
-public:
-       MotionBlockXText(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionWindow *gui;
-       MotionMain *plugin;
-};
-
-class MotionBlockYText : public BC_TextBox
-{
-public:
-       MotionBlockYText(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionWindow *gui;
-       MotionMain *plugin;
-};
-
-class GlobalSearchPositions : public BC_PopupMenu
-{
-public:
-       GlobalSearchPositions(MotionMain *plugin,
-               int x,
-               int y,
-               int w);
-       void create_objects();
-       int handle_event();
-       MotionMain *plugin;
-};
-
-class RotationSearchPositions : public BC_PopupMenu
-{
-public:
-       RotationSearchPositions(MotionMain *plugin,
-               int x,
-               int y,
-               int w);
-       void create_objects();
-       int handle_event();
-       MotionMain *plugin;
-};
-
-class MotionMagnitude : public BC_IPot
-{
-public:
-       MotionMagnitude(MotionMain *plugin,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-};
-
-class MotionRMagnitude : public BC_IPot
-{
-public:
-       MotionRMagnitude(MotionMain *plugin,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-};
-
-class MotionReturnSpeed : public BC_IPot
-{
-public:
-       MotionReturnSpeed(MotionMain *plugin,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-};
-
-
-class MotionRReturnSpeed : public BC_IPot
-{
-public:
-       MotionRReturnSpeed(MotionMain *plugin,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-};
-
-
-class MotionDrawVectors : public BC_CheckBox
-{
-public:
-       MotionDrawVectors(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionMain *plugin;
-       MotionWindow *gui;
-};
-
-
-class MotionGlobal : public BC_CheckBox
-{
-public:
-       MotionGlobal(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionWindow *gui;
-       MotionMain *plugin;
-};
-
-class MotionRotate : public BC_CheckBox
-{
-public:
-       MotionRotate(MotionMain *plugin,
-               MotionWindow *gui,
-               int x,
-               int y);
-       int handle_event();
-       MotionWindow *gui;
-       MotionMain *plugin;
-};
-
-
-
-class MotionWindow : public PluginClientWindow
-{
-public:
-       MotionWindow(MotionMain *plugin);
-       ~MotionWindow();
-
-       void create_objects();
-       void update_mode();
-       char* get_radius_title();
-
-       GlobalRange *global_range_w;
-       GlobalRange *global_range_h;
-       RotationRange *rotation_range;
-       RotationCenter *rotation_center;
-       BlockSize *global_block_w;
-       BlockSize *global_block_h;
-       BlockSize *rotation_block_w;
-       BlockSize *rotation_block_h;
-       MotionBlockX *block_x;
-       MotionBlockY *block_y;
-       MotionBlockXText *block_x_text;
-       MotionBlockYText *block_y_text;
-       GlobalSearchPositions *global_search_positions;
-       RotationSearchPositions *rotation_search_positions;
-       MotionMagnitude *magnitude;
-       MotionRMagnitude *rotate_magnitude;
-       MotionReturnSpeed *return_speed;
-       MotionRReturnSpeed *rotate_return_speed;
-       ActionType *action_type;
-       MotionDrawVectors *vectors;
-       MotionGlobal *global;
-       MotionRotate *rotate;
-       TrackSingleFrame *track_single;
-       TrackFrameNumber *track_frame_number;
-       TrackPreviousFrame *track_previous;
-       PreviousFrameSameBlock *previous_same;
-       MasterLayer *master_layer;
-       TrackingType *tracking_type;
-       TrackDirection *track_direction;
-
-       MotionMain *plugin;
-};
-
-
-
-
-
-
-
-
-
index 7d660b353a120102fb8a0639c3d176f8649daa73..ed6768037e5deb70bd7d38a2bed497b226f3f76a 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 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
@@ -33,7 +33,6 @@
 #include "mutex.h"
 #include "overlayframe.h"
 #include "rotateframe.h"
-#include "rotatescan.h"
 #include "transportque.h"
 
 
@@ -42,6 +41,7 @@
 
 REGISTER_PLUGIN(MotionMain)
 
+
 #undef DEBUG
 
 // #ifndef DEBUG
@@ -52,35 +52,48 @@ REGISTER_PLUGIN(MotionMain)
 
 MotionConfig::MotionConfig()
 {
-       global_range_w = 5;
-       global_range_h = 5;
+       global_range_w = 10;
+       global_range_h = 10;
        rotation_range = 5;
        rotation_center = 0;
        block_count = 1;
-       global_block_w = MIN_BLOCK;
-       global_block_h = MIN_BLOCK;
+       global_block_w = 50; // MIN_BLOCK;
+       global_block_h = 50; // MIN_BLOCK;
 //     rotation_block_w = MIN_BLOCK;
 //     rotation_block_h = MIN_BLOCK;
        block_x = 50;
        block_y = 50;
-//     global_positions = 256;
-//     rotate_positions = 4;
-       magnitude = 100;
-       rotate_magnitude = 90;
-       return_speed = 0;
-       rotate_return_speed = 0;
-       action_type = MotionScan::STABILIZE;
-//     global = 1;
+       global_positions = 256;
+       rotate_positions = 4;
+       magnitude = 25;
+       rotate_magnitude = 30;
+       return_speed = 8;
+       rotate_return_speed = 8;
+       action_type = MotionScan::STABILIZE_PIXEL;
+       global = 1;
        rotate = 1;
-       tracking_type = MotionScan::NO_CALCULATE;
-       draw_vectors = 1;
-       tracking_object = MotionScan::TRACK_SINGLE;
+       addtrackedframeoffset = 0;
+       tracking_type = MotionScan::CALCULATE;
+       draw_vectors = 0;
+       tracking_object = MotionScan::TRACK_PREVIOUS;
        track_frame = 0;
        bottom_is_master = 1;
        horizontal_only = 0;
        vertical_only = 0;
 }
 
+void MotionConfig::set_cpus(int cpus)
+{
+       int gpos = 64, gpos_limit = 16 * cpus;
+       if( gpos_limit > 131072 ) gpos_limit = 131072;
+       while( gpos < gpos_limit ) gpos *= 2;
+       global_positions = gpos;
+       int rpos = 4, rpos_limit = cpus / 4;
+       if( rpos_limit > 32 ) gpos_limit = 32;
+       while( rpos < rpos_limit ) rpos *= 2;
+       rotate_positions = rpos;
+}
+
 void MotionConfig::boundaries()
 {
        CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS);
@@ -101,8 +114,9 @@ int MotionConfig::equivalent(MotionConfig &that)
                rotation_range == that.rotation_range &&
                rotation_center == that.rotation_center &&
                action_type == that.action_type &&
-//             global == that.global &&
+               global == that.global &&
                rotate == that.rotate &&
+               addtrackedframeoffset == that.addtrackedframeoffset &&
                draw_vectors == that.draw_vectors &&
                block_count == that.block_count &&
                global_block_w == that.global_block_w &&
@@ -111,8 +125,8 @@ int MotionConfig::equivalent(MotionConfig &that)
 //             rotation_block_h == that.rotation_block_h &&
                EQUIV(block_x, that.block_x) &&
                EQUIV(block_y, that.block_y) &&
-//             global_positions == that.global_positions &&
-//             rotate_positions == that.rotate_positions &&
+               global_positions == that.global_positions &&
+               rotate_positions == that.rotate_positions &&
                magnitude == that.magnitude &&
                return_speed == that.return_speed &&
                rotate_return_speed == that.rotate_return_speed &&
@@ -131,15 +145,16 @@ void MotionConfig::copy_from(MotionConfig &that)
        rotation_range = that.rotation_range;
        rotation_center = that.rotation_center;
        action_type = that.action_type;
-//     global = that.global;
+       global = that.global;
        rotate = that.rotate;
+       addtrackedframeoffset = that.addtrackedframeoffset;
        tracking_type = that.tracking_type;
        draw_vectors = that.draw_vectors;
        block_count = that.block_count;
        block_x = that.block_x;
        block_y = that.block_y;
-//     global_positions = that.global_positions;
-//     rotate_positions = that.rotate_positions;
+       global_positions = that.global_positions;
+       rotate_positions = that.rotate_positions;
        global_block_w = that.global_block_w;
        global_block_h = that.global_block_h;
 //     rotation_block_w = that.rotation_block_w;
@@ -170,13 +185,14 @@ void MotionConfig::interpolate(MotionConfig &prev,
        rotation_range = prev.rotation_range;
        rotation_center = prev.rotation_center;
        action_type = prev.action_type;
-//     global = prev.global;
+       global = prev.global;
        rotate = prev.rotate;
+       addtrackedframeoffset = prev.addtrackedframeoffset;
        tracking_type = prev.tracking_type;
        draw_vectors = prev.draw_vectors;
        block_count = prev.block_count;
-//     global_positions = prev.global_positions;
-//     rotate_positions = prev.rotate_positions;
+       global_positions = prev.global_positions;
+       rotate_positions = prev.rotate_positions;
        global_block_w = prev.global_block_w;
        global_block_h = prev.global_block_h;
 //     rotation_block_w = prev.rotation_block_w;
@@ -215,7 +231,7 @@ MotionMain::MotionMain(PluginServer *server)
 {
        engine = 0;
        rotate_engine = 0;
-//     motion_rotate = 0;
+       motion_rotate = 0;
        total_dx = 0;
        total_dy = 0;
        total_angle = 0;
@@ -234,6 +250,8 @@ MotionMain::MotionMain(PluginServer *server)
        current_rotate_ref = 0;
        rotate_target_src = 0;
        rotate_target_dst = 0;
+
+       config.set_cpus(get_project_smp() + 1);
 }
 
 MotionMain::~MotionMain()
@@ -244,7 +262,7 @@ MotionMain::~MotionMain()
        delete [] search_area;
        delete temp_frame;
        delete rotate_engine;
-//     delete motion_rotate;
+       delete motion_rotate;
 
 
        delete prev_global_ref;
@@ -277,11 +295,11 @@ void MotionMain::update_gui()
                {
                        thread->window->lock_window("MotionMain::update_gui");
 
-//                     char string[BCTEXTLEN];
-//                     sprintf(string, "%d", config.global_positions);
-//                     ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
-//                     sprintf(string, "%d", config.rotate_positions);
-//                     ((MotionWindow*)thread->window)->rotation_search_positions->set_text(string);
+                       char string[BCTEXTLEN];
+                       sprintf(string, "%d", config.global_positions);
+                       ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
+                       sprintf(string, "%d", config.rotate_positions);
+                       ((MotionWindow*)thread->window)->rotation_search_positions->set_text(string);
 
                        ((MotionWindow*)thread->window)->global_block_w->update(config.global_block_w);
                        ((MotionWindow*)thread->window)->global_block_h->update(config.global_block_h);
@@ -336,8 +354,8 @@ void MotionMain::save_data(KeyFrame *keyframe)
        output.tag.set_title("MOTION");
 
        output.tag.set_property("BLOCK_COUNT", config.block_count);
-//     output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
-//     output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
+       output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
+       output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
        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("ROTATION_BLOCK_W", config.rotation_block_w);
@@ -353,8 +371,9 @@ void MotionMain::save_data(KeyFrame *keyframe)
        output.tag.set_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
        output.tag.set_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
        output.tag.set_property("ACTION_TYPE", config.action_type);
-//     output.tag.set_property("GLOBAL", config.global);
+       output.tag.set_property("GLOBAL", config.global);
        output.tag.set_property("ROTATE", config.rotate);
+       output.tag.set_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
        output.tag.set_property("TRACKING_TYPE", config.tracking_type);
        output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
        output.tag.set_property("TRACKING_OBJECT", config.tracking_object);
@@ -385,8 +404,8 @@ void MotionMain::read_data(KeyFrame *keyframe)
                        if(input.tag.title_is("MOTION"))
                        {
                                config.block_count = input.tag.get_property("BLOCK_COUNT", config.block_count);
-//                             config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
-//                             config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
+                               config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
+                               config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
                                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.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
@@ -402,8 +421,9 @@ void MotionMain::read_data(KeyFrame *keyframe)
                                config.rotate_magnitude = input.tag.get_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
                                config.rotate_return_speed = input.tag.get_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
                                config.action_type = input.tag.get_property("ACTION_TYPE", config.action_type);
-//                             config.global = input.tag.get_property("GLOBAL", config.global);
+                               config.global = input.tag.get_property("GLOBAL", config.global);
                                config.rotate = input.tag.get_property("ROTATE", config.rotate);
+                               config.addtrackedframeoffset = input.tag.get_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
                                config.tracking_type = input.tag.get_property("TRACKING_TYPE", config.tracking_type);
                                config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
                                config.tracking_object = input.tag.get_property("TRACKING_OBJECT", config.tracking_object);
@@ -441,39 +461,30 @@ void MotionMain::allocate_temp(int w, int h, int color_model)
 
 void MotionMain::process_global()
 {
-       int w = current_global_ref->get_w();
-       int h = current_global_ref->get_h();
-
 
        if(!engine) engine = new MotionScan(PluginClient::get_project_smp() + 1,
                PluginClient::get_project_smp() + 1);
 
 // Determine if frames changed
-// printf("MotionMain::process_global %d block_y=%f total_dy=%d\n",
-//  __LINE__, config.block_y * h / 100, total_dy);
        engine->scan_frame(current_global_ref,
                prev_global_ref,
-               config.global_range_w * w / 100,
-               config.global_range_h * h / 100,
-               config.global_block_w * w / 100,
-               config.global_block_h * h / 100,
-               config.block_x * w / 100,
-               config.block_y * h / 100,
+               config.global_range_w,
+               config.global_range_h,
+               config.global_block_w,
+               config.global_block_h,
+               config.block_x,
+               config.block_y,
                config.tracking_object,
                config.tracking_type,
                config.action_type,
                config.horizontal_only,
                config.vertical_only,
                get_source_position(),
+               config.global_positions,
                total_dx,
                total_dy,
                0,
-               0,
-               1, // do_motion
-               config.rotate, // do_rotate
-               config.rotation_center,
-               config.rotation_range);
-
+               0);
        current_dx = engine->dx_result;
        current_dy = engine->dy_result;
 
@@ -485,8 +496,9 @@ void MotionMain::process_global()
                total_dy = (int64_t)total_dy * (100 - config.return_speed) / 100;
                total_dx += engine->dx_result;
                total_dy += engine->dy_result;
-// printf("MotionMain::process_global %d total_dy=%d engine->dy_result=%d\n",
-//  __LINE__, total_dy, engine->dy_result);
+// printf("MotionMain::process_global total_dx=%d engine->dx_result=%d\n",
+// total_dx,
+// engine->dx_result);
        }
        else
 // Make accumulation vector current
@@ -498,27 +510,43 @@ void MotionMain::process_global()
 // Clamp accumulation vector
        if(config.magnitude < 100)
        {
-               //int block_w = (int64_t)config.global_block_w * w / 100;
-               //int block_h = (int64_t)config.global_block_h * h / 100;
-               int block_x_orig = (int64_t)(config.block_x * w / 100);
+               //int block_w = (int64_t)config.global_block_w *
+               //              current_global_ref->get_w() / 100;
+               //int block_h = (int64_t)config.global_block_h *
+               //              current_global_ref->get_h() / 100;
+               int block_x_orig = (int64_t)(config.block_x *
+                       current_global_ref->get_w() /
+                       100);
                int block_y_orig = (int64_t)(config.block_y *
-                       current_global_ref->get_h() / h / 100);
+                       current_global_ref->get_h() /
+                       100);
 
-               int max_block_x = (int64_t)(w - block_x_orig) *
-                       OVERSAMPLE * config.magnitude / 100;
-               int max_block_y = (int64_t)(h - block_y_orig) *
-                       OVERSAMPLE * config.magnitude / 100;
+               int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
+                       OVERSAMPLE *
+                       config.magnitude /
+                       100;
+               int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
+                       OVERSAMPLE *
+                       config.magnitude /
+                       100;
                int min_block_x = (int64_t)-block_x_orig *
-                       OVERSAMPLE * config.magnitude / 100;
+                       OVERSAMPLE *
+                       config.magnitude /
+                       100;
                int min_block_y = (int64_t)-block_y_orig *
-                       OVERSAMPLE * config.magnitude / 100;
+                       OVERSAMPLE *
+                       config.magnitude /
+                       100;
 
                CLAMP(total_dx, min_block_x, max_block_x);
                CLAMP(total_dy, min_block_y, max_block_y);
        }
 
-// printf("MotionMain::process_global %d total_dx=%d total_dy=%d\n",
-//  __LINE__, total_dx, total_dy);
+#ifdef DEBUG
+printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
+(float)total_dx / OVERSAMPLE,
+(float)total_dy / OVERSAMPLE);
+#endif
 
        if(config.tracking_object != MotionScan::TRACK_SINGLE && !config.rotate)
        {
@@ -547,6 +575,7 @@ void MotionMain::process_global()
                        dx = -(int)(total_dx / OVERSAMPLE);
                        dy = -(int)(total_dy / OVERSAMPLE);
                        break;
+                       break;
                case MotionScan::TRACK:
                        interpolation = CUBIC_LINEAR;
                        dx = (float)total_dx / OVERSAMPLE;
@@ -588,11 +617,9 @@ void MotionMain::process_rotation()
        int block_x;
        int block_y;
 
-// Always require global
 // Convert the previous global reference into the previous rotation reference.
 // Convert global target destination into rotation target source.
-//     if(config.global)
-       if(1)
+       if(config.global)
        {
                if(!overlayer)
                        overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
@@ -657,17 +684,17 @@ void MotionMain::process_rotation()
 
 
 // Get rotation
-//     if(!motion_rotate)
-//             motion_rotate = new RotateScan(this,
-//                     get_project_smp() + 1,
-//                     get_project_smp() + 1);
-//
-//     current_angle = motion_rotate->scan_frame(prev_rotate_ref,
-//             current_rotate_ref,
-//             block_x,
-//             block_y);
-
-       current_angle = engine->dr_result;
+       if(!motion_rotate)
+               motion_rotate = new RotateScan(this,
+                       get_project_smp() + 1,
+                       get_project_smp() + 1);
+
+       current_angle = motion_rotate->scan_frame(prev_rotate_ref,
+               current_rotate_ref,
+               block_x,
+               block_y);
+
+
 
 // Add current rotation to accumulation
        if(config.tracking_object != MotionScan::TRACK_SINGLE)
@@ -683,13 +710,13 @@ void MotionMain::process_rotation()
                        CLAMP(total_angle, -config.rotate_magnitude, config.rotate_magnitude);
                }
 
-//             if(!config.global)
-//             {
+               if(!config.global)
+               {
 // Transfer current reference frame to previous reference frame and update
 // counter.
-//                     prev_rotate_ref->copy_from(current_rotate_ref);
-//                     previous_frame_number = get_source_position();
-//             }
+                       prev_rotate_ref->copy_from(current_rotate_ref);
+                       previous_frame_number = get_source_position();
+               }
        }
        else
        {
@@ -741,8 +768,7 @@ printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
 
                        case MotionScan::STABILIZE:
                        case MotionScan::STABILIZE_PIXEL:
-//                             if(config.global)
-                               if(1)
+                               if(config.global)
                                {
 // Use origin of global stabilize operation
 //                                     rotate_engine->set_pivot((int)(rotate_target_dst->get_w() *
@@ -776,7 +802,6 @@ printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
                }
 
 
-printf("MotionMain::process_rotation angle=%f\n", angle);
                rotate_engine->rotate(rotate_target_dst, rotate_target_src, angle);
 // overlayer->overlay(rotate_target_dst,
 //     prev_rotate_ref,
@@ -898,7 +923,7 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
        }
 
 
-//     if(!config.global && !config.rotate) skip_current = 1;
+       if(!config.global && !config.rotate) skip_current = 1;
 
 
 
@@ -934,8 +959,7 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
 
 
 // Get the global pointers.  Here we walk through the sequence of events.
-//     if(config.global)
-       if(1)
+       if(config.global)
        {
 // Assume global only.  Global reads previous frame and compares
 // with current frame to get the current translation.
@@ -1048,14 +1072,13 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
 
 
 
-//PRINT_TRACE
-//printf("skip_current=%d config.global=%d\n", skip_current, config.global);
+
 
 
        if(!skip_current)
        {
 // Get position change from previous frame to current frame
-               /* if(config.global) */ process_global();
+               if(config.global) process_global();
 // Get rotation change from previous frame to current frame
                if(config.rotate) process_rotation();
 //frame[target_layer]->copy_from(prev_rotate_ref);
@@ -1119,9 +1142,7 @@ void MotionMain::draw_vectors(VFrame *frame)
        int search_x2, search_y2;
 
 
-// always processing global
-//     if(config.global)
-       if(1)
+       if(config.global)
        {
 // Get vector
 // Start of vector is center of previous block.
@@ -1438,3 +1459,439 @@ void MotionMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
 
 
 
+
+
+
+
+
+
+
+
+
+RotateScanPackage::RotateScanPackage()
+{
+}
+
+
+RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
+ : LoadClient(server)
+{
+       this->server = server;
+       this->plugin = plugin;
+       rotater = 0;
+       temp = 0;
+}
+
+RotateScanUnit::~RotateScanUnit()
+{
+       delete rotater;
+       delete temp;
+}
+
+void RotateScanUnit::process_package(LoadPackage *package)
+{
+       if(server->skip) return;
+       RotateScanPackage *pkg = (RotateScanPackage*)package;
+
+       if((pkg->difference = server->get_cache(pkg->angle)) < 0)
+       {
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+               int color_model = server->previous_frame->get_color_model();
+               int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+               int row_bytes = server->previous_frame->get_bytes_per_line();
+
+               if(!rotater)
+                       rotater = new AffineEngine(1, 1);
+               if(!temp) temp = new VFrame(0,
+                       -1,
+                       server->previous_frame->get_w(),
+                       server->previous_frame->get_h(),
+                       color_model,
+                       -1);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+
+
+// Rotate original block size
+//             rotater->set_viewport(server->block_x1,
+//                     server->block_y1,
+//                     server->block_x2 - server->block_x1,
+//                     server->block_y2 - server->block_y1);
+               rotater->set_in_viewport(server->block_x1,
+                       server->block_y1,
+                       server->block_x2 - server->block_x1,
+                       server->block_y2 - server->block_y1);
+               rotater->set_out_viewport(server->block_x1,
+                       server->block_y1,
+                       server->block_x2 - server->block_x1,
+                       server->block_y2 - server->block_y1);
+//             rotater->set_pivot(server->block_x, server->block_y);
+               rotater->set_in_pivot(server->block_x, server->block_y);
+               rotater->set_out_pivot(server->block_x, server->block_y);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+               rotater->rotate(temp,
+                       server->previous_frame,
+                       pkg->angle);
+
+// Scan reduced block size
+//plugin->output_frame->copy_from(server->current_frame);
+//plugin->output_frame->copy_from(temp);
+// printf("RotateScanUnit::process_package %d %d %d %d %d\n",
+// __LINE__,
+// server->scan_x,
+// server->scan_y,
+// server->scan_w,
+// server->scan_h);
+// Clamp coordinates
+               int x1 = server->scan_x;
+               int y1 = server->scan_y;
+               int x2 = x1 + server->scan_w;
+               int y2 = y1 + server->scan_h;
+               x2 = MIN(temp->get_w(), x2);
+               y2 = MIN(temp->get_h(), y2);
+               x2 = MIN(server->current_frame->get_w(), x2);
+               y2 = MIN(server->current_frame->get_h(), y2);
+               x1 = MAX(0, x1);
+               y1 = MAX(0, y1);
+
+               if(x2 > x1 && y2 > y1)
+               {
+                       pkg->difference = MotionScan::abs_diff(
+                               temp->get_rows()[y1] + x1 * pixel_size,
+                               server->current_frame->get_rows()[y1] + x1 * pixel_size,
+                               row_bytes,
+                               x2 - x1,
+                               y2 - y1,
+                               color_model);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+                       server->put_cache(pkg->angle, pkg->difference);
+               }
+#if 0
+       VFrame png(x2-x1, y2-y1, BC_RGB888, -1);
+       png.transfer_from(temp, 0, x1, y1, x2-x1, y2-y1);
+       char fn[64];
+       sprintf(fn,"%s%f.png","/tmp/temp",pkg->angle); png.write_png(fn);
+       png.transfer_from(server->current_frame, 0, x1, y1, x2-x1, y2-y1);
+       sprintf(fn,"%s%f.png","/tmp/curr",pkg->angle); png.write_png(fn);
+printf("RotateScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%jd\n",
+ server->block_x1, server->block_y1, server->block_x2 - server->block_x1, server->block_y2 - server->block_y1,
+ server->block_x,  server->block_y,  pkg->angle,  server->scan_w, server->scan_h, pkg->difference);
+#endif
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+RotateScan::RotateScan(MotionMain *plugin,
+       int total_clients,
+       int total_packages)
+ : LoadServer(
+//1, 1
+total_clients, total_packages
+)
+{
+       this->plugin = plugin;
+       cache_lock = new Mutex("RotateScan::cache_lock");
+}
+
+
+RotateScan::~RotateScan()
+{
+       delete cache_lock;
+}
+
+void RotateScan::init_packages()
+{
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
+               pkg->angle = i *
+                       (scan_angle2 - scan_angle1) /
+                       (total_steps - 1) +
+                       scan_angle1;
+       }
+}
+
+LoadClient* RotateScan::new_client()
+{
+       return new RotateScanUnit(this, plugin);
+}
+
+LoadPackage* RotateScan::new_package()
+{
+       return new RotateScanPackage;
+}
+
+
+float RotateScan::scan_frame(VFrame *previous_frame,
+       VFrame *current_frame,
+       int block_x,
+       int block_y)
+{
+       skip = 0;
+       this->block_x = block_x;
+       this->block_y = block_y;
+
+//printf("RotateScan::scan_frame %d\n", __LINE__);
+       switch(plugin->config.tracking_type)
+       {
+               case MotionScan::NO_CALCULATE:
+                       result = plugin->config.rotation_center;
+                       skip = 1;
+                       break;
+
+               case MotionScan::LOAD:
+               {
+                       char string[BCTEXTLEN];
+                       sprintf(string, "%s%06jd",
+                                ROTATION_FILE, plugin->get_source_position());
+                       FILE *input = fopen(string, "r");
+                       if(input)
+                       {
+                               fscanf(input, "%f", &result);
+                               fclose(input);
+                               skip = 1;
+                       }
+                       else
+                       {
+                               perror("RotateScan::scan_frame LOAD");
+                       }
+                       break;
+               }
+       }
+
+
+
+
+
+
+
+
+       this->previous_frame = previous_frame;
+       this->current_frame = current_frame;
+       int w = current_frame->get_w();
+       int h = current_frame->get_h();
+       int block_w = w * plugin->config.global_block_w / 100;
+       int block_h = h * plugin->config.global_block_h / 100;
+
+       if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
+       if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
+       if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
+       if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
+
+       block_x1 = this->block_x - block_w / 2;
+       block_x2 = this->block_x + block_w / 2;
+       block_y1 = this->block_y - block_h / 2;
+       block_y2 = this->block_y + block_h / 2;
+
+// Calculate the maximum area available to scan after rotation.
+// Must be calculated from the starting range because of cache.
+// Get coords of rectangle after rotation.
+       double center_x = this->block_x;
+       double center_y = this->block_y;
+       double max_angle = plugin->config.rotation_range;
+       double base_angle1 = atan((float)block_h / block_w);
+       double base_angle2 = atan((float)block_w / block_h);
+       double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
+       double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
+       double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
+       double x1 = center_x - cos(target_angle1) * radius;
+       double y1 = center_y - sin(target_angle1) * radius;
+       double x2 = center_x + sin(target_angle2) * radius;
+       double y2 = center_y - cos(target_angle2) * radius;
+       double x3 = center_x - sin(target_angle2) * radius;
+       double y3 = center_y + cos(target_angle2) * radius;
+
+// Track top edge to find greatest area.
+       double max_area1 = 0;
+       //double max_x1 = 0;
+       double max_y1 = 0;
+       for(double x = x1; x < x2; x++)
+       {
+               double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+               if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area1)
+                       {
+                               max_area1 = area;
+                               //max_x1 = x;
+                               max_y1 = y;
+                       }
+               }
+       }
+
+// Track left edge to find greatest area.
+       double max_area2 = 0;
+       double max_x2 = 0;
+       //double max_y2 = 0;
+       for(double y = y1; y < y3; y++)
+       {
+               double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
+               if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area2)
+                       {
+                               max_area2 = area;
+                               max_x2 = x;
+                               //max_y2 = y;
+                       }
+               }
+       }
+
+       double max_x, max_y;
+       max_x = max_x2;
+       max_y = max_y1;
+
+// Get reduced scan coords
+       scan_w = (int)(fabs(max_x - center_x) * 2);
+       scan_h = (int)(fabs(max_y - center_y) * 2);
+       scan_x = (int)(center_x - scan_w / 2);
+       scan_y = (int)(center_y - scan_h / 2);
+// printf("RotateScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n",
+// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
+// printf("    angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
+
+// Determine min angle from size of block
+       double angle1 = atan((double)block_h / block_w);
+       double angle2 = atan((double)(block_h - 1) / (block_w + 1));
+       double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
+       min_angle = MAX(min_angle, MIN_ANGLE);
+
+//printf("RotateScan::scan_frame %d min_angle=%f\n", __LINE__, min_angle * 360 / 2 / M_PI);
+
+       cache.remove_all_objects();
+
+
+       if(!skip)
+       {
+               if(previous_frame->data_matches(current_frame))
+               {
+//printf("RotateScan::scan_frame: frames match.  Skipping.\n");
+                       result = plugin->config.rotation_center;
+                       skip = 1;
+               }
+       }
+
+       if(!skip)
+       {
+// Initial search range
+               float angle_range = max_angle;
+               result = plugin->config.rotation_center;
+               total_steps = plugin->config.rotate_positions;
+
+
+               while(angle_range >= min_angle * total_steps)
+               {
+                       scan_angle1 = result - angle_range;
+                       scan_angle2 = result + angle_range;
+
+
+                       set_package_count(total_steps);
+//set_package_count(1);
+                       process_packages();
+
+                       int64_t min_difference = -1;
+                       for(int i = 0; i < get_total_packages(); i++)
+                       {
+                               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
+                               if(pkg->difference < min_difference || min_difference == -1)
+                               {
+                                       min_difference = pkg->difference;
+                                       result = pkg->angle;
+                               }
+//break;
+                       }
+
+                       angle_range /= 2;
+
+//break;
+               }
+       }
+
+//printf("RotateScan::scan_frame %d\n", __LINE__);
+
+       if(!skip && plugin->config.tracking_type == MotionScan::SAVE)
+       {
+               char string[BCTEXTLEN];
+               sprintf(string, "%s%06jd",
+                       ROTATION_FILE, plugin->get_source_position());
+               FILE *output = fopen(string, "w");
+               if(output)
+               {
+                       fprintf(output, "%f\n", result);
+                       fclose(output);
+               }
+               else
+               {
+                       perror("RotateScan::scan_frame SAVE");
+               }
+       }
+
+//printf("RotateScan::scan_frame %d angle=%f\n", __LINE__, result);
+
+
+
+       return result;
+}
+
+int64_t RotateScan::get_cache(float angle)
+{
+       int64_t result = -1;
+       cache_lock->lock("RotateScan::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               RotateScanCache *ptr = cache.values[i];
+               if(fabs(ptr->angle - angle) <= MIN_ANGLE)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void RotateScan::put_cache(float angle, int64_t difference)
+{
+       RotateScanCache *ptr = new RotateScanCache(angle, difference);
+       cache_lock->lock("RotateScan::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+
+
+
+
+RotateScanCache::RotateScanCache(float angle, int64_t difference)
+{
+       this->angle = angle;
+       this->difference = difference;
+}
+
+
+
index 5b359f4b19ab6daf0e5cda0d122bbe89f3c5df56..e0011d751171bc8707ee32361650a65692c25a47 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
+ * 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
 #include "motionwindow.inc"
 #include "overlayframe.inc"
 #include "pluginvclient.h"
-#include "rotatescan.inc"
+#include "rotateframe.inc"
 #include "vframe.inc"
 
 class MotionMain;
 class MotionWindow;
+class RotateScan;
 
 
 
@@ -63,6 +64,7 @@ class MotionWindow;
 // Precision of rotation
 #define MIN_ANGLE 0.0001
 
+#define ROTATION_FILE "/tmp/r"
 
 class MotionConfig
 {
@@ -77,6 +79,7 @@ public:
                int64_t next_frame,
                int64_t current_frame);
        void boundaries();
+       void set_cpus(int cpus);
 
        int block_count;
        int global_range_w;
@@ -96,8 +99,8 @@ public:
 //     int rotation_block_w;
 //     int rotation_block_h;
 // Number of search positions in each refinement of the log search
-//     int global_positions;
-//     int rotate_positions;
+       int global_positions;
+       int rotate_positions;
 // Block position in percentage 0 - 100
        double block_x;
        double block_y;
@@ -106,6 +109,7 @@ public:
        int vertical_only;
        int global;
        int rotate;
+       int addtrackedframeoffset;
 // Track or stabilize, single pixel, scan only, or nothing
        int action_type;
 // Recalculate, no calculate, save, or load coordinates from disk
@@ -178,7 +182,7 @@ public:
 // It is moved to compensate for motion and copied to the previous_frame.
        VFrame *temp_frame;
        MotionScan *engine;
-//     RotateScan *motion_rotate;
+       RotateScan *motion_rotate;
        OverlayFrame *overlayer;
        AffineEngine *rotate_engine;
 
@@ -244,6 +248,110 @@ public:
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+class RotateScanPackage : public LoadPackage
+{
+public:
+       RotateScanPackage();
+       float angle;
+       int64_t difference;
+};
+
+class RotateScanCache
+{
+public:
+       RotateScanCache(float angle, int64_t difference);
+       float angle;
+       int64_t difference;
+};
+
+class RotateScanUnit : public LoadClient
+{
+public:
+       RotateScanUnit(RotateScan *server, MotionMain *plugin);
+       ~RotateScanUnit();
+
+       void process_package(LoadPackage *package);
+
+       RotateScan *server;
+       MotionMain *plugin;
+       AffineEngine *rotater;
+       VFrame *temp;
+};
+
+class RotateScan : public LoadServer
+{
+public:
+       RotateScan(MotionMain *plugin,
+               int total_clients,
+               int total_packages);
+       ~RotateScan();
+
+       friend class RotateScanUnit;
+
+       void init_packages();
+       LoadClient* new_client();
+       LoadPackage* new_package();
+
+// Invoke the motion engine for a search
+// Frame before rotation
+       float scan_frame(VFrame *previous_frame,
+// Frame after rotation
+               VFrame *current_frame,
+// Pivot
+               int block_x,
+               int block_y);
+       int64_t get_cache(float angle);
+       void put_cache(float angle, int64_t difference);
+
+
+// Angle result
+       float result;
+
+private:
+       VFrame *previous_frame;
+// Frame after motion
+       VFrame *current_frame;
+
+       MotionMain *plugin;
+       int skip;
+
+// Pivot
+       int block_x;
+       int block_y;
+// Block to rotate
+       int block_x1;
+       int block_x2;
+       int block_y1;
+       int block_y2;
+// Area to compare
+       int scan_x;
+       int scan_y;
+       int scan_w;
+       int scan_h;
+// Range of angles to compare
+       float scan_angle1, scan_angle2;
+       int total_steps;
+
+       ArrayList<RotateScanCache*> cache;
+       Mutex *cache_lock;
+};
+
+
+
+
 #endif
 
 
index cf71a2a44f78873aafdfab11f35b693fa34785d8..01c3594729637e0450a96ee327dd08c09088016b 100644 (file)
@@ -2,21 +2,21 @@
 /*
  * 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 MOTION_INC
index 67e8460e8671de4cb464e721a22a2c6edd1511cb..b1a533ef850477a9c7412d39e92c45d5d60c2a09 100644 (file)
@@ -1,46 +1,38 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
- *
+ * Copyright (C) 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 "affine.h"
-#include "bcsignals.h"
 #include "clip.h"
+//#include "../downsample/downsampleengine.h"
+//#include "motion.h"
 #include "motionscan.h"
 #include "mutex.h"
 #include "vframe.h"
 
-
 #include <math.h>
-#include <stdlib.h>
-#include <string.h>
 
 // The module which does the actual scanning
 
-// starting level of detail
-#define STARTING_DOWNSAMPLE 16
-// minimum size in each level of detail
-#define MIN_DOWNSAMPLED_SIZE 16
-// minimum scan range
-#define MIN_DOWNSAMPLED_SCAN 4
-// scan range for subpixel mode
-#define SUBPIXEL_RANGE 4
+
+
+
 
 MotionScanPackage::MotionScanPackage()
  : LoadPackage()
@@ -57,124 +49,116 @@ MotionScanUnit::MotionScanUnit(MotionScan *server)
  : LoadClient(server)
 {
        this->server = server;
+       cache_lock = new Mutex("MotionScanUnit::cache_lock");
 }
 
 MotionScanUnit::~MotionScanUnit()
 {
+       delete cache_lock;
 }
 
 
-void MotionScanUnit::single_pixel(MotionScanPackage *pkg)
+
+void MotionScanUnit::process_package(LoadPackage *package)
 {
+       MotionScanPackage *pkg = (MotionScanPackage*)package;
        //int w = server->current_frame->get_w();
        //int h = server->current_frame->get_h();
        int color_model = server->current_frame->get_color_model();
        int pixel_size = BC_CModels::calculate_pixelsize(color_model);
        int row_bytes = server->current_frame->get_bytes_per_line();
 
-// printf("MotionScanUnit::process_package %d search_x=%d search_y=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n",
-// __LINE__,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->scan_x1,
-// pkg->scan_y1,
-// pkg->scan_x2,
-// pkg->scan_y2,
-// server->x_steps,
-// server->y_steps);
 
-// Pointers to first pixel in each block
-       unsigned char *prev_ptr = server->previous_frame->get_rows()[
-               pkg->search_y] +
-               pkg->search_x * pixel_size;
-       unsigned char *current_ptr = 0;
 
-       if(server->do_rotate)
-       {
-               current_ptr = server->rotated_current[pkg->angle_step]->get_rows()[
-                       pkg->block_y1] +
-                       pkg->block_x1 * pixel_size;
-       }
-       else
-       {
-               current_ptr = server->current_frame->get_rows()[
-                       pkg->block_y1] +
-                       pkg->block_x1 * pixel_size;
-       }
 
-// Scan block
-       pkg->difference1 = MotionScan::abs_diff(prev_ptr,
-               current_ptr,
-               row_bytes,
-               pkg->block_x2 - pkg->block_x1,
-               pkg->block_y2 - pkg->block_y1,
-               color_model);
-
-// printf("MotionScanUnit::process_package %d angle_step=%d diff=%d\n",
-// __LINE__,
-// pkg->angle_step,
-// pkg->difference1);
-// printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n",
-// __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
-}
 
-void MotionScanUnit::subpixel(MotionScanPackage *pkg)
-{
-//PRINT_TRACE
-       //int w = server->current_frame->get_w();
-       //int h = server->current_frame->get_h();
-       int color_model = server->current_frame->get_color_model();
-       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
-       int row_bytes = server->current_frame->get_bytes_per_line();
-       unsigned char *prev_ptr = server->previous_frame->get_rows()[
-               pkg->search_y] +
-               pkg->search_x * pixel_size;
-// neglect rotation
-       unsigned char *current_ptr = server->current_frame->get_rows()[
-               pkg->block_y1] +
-               pkg->block_x1 * pixel_size;
 
-// With subpixel, there are two ways to compare each position, one by shifting
-// the previous frame and two by shifting the current frame.
-       pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr,
-               current_ptr,
-               row_bytes,
-               pkg->block_x2 - pkg->block_x1,
-               pkg->block_y2 - pkg->block_y1,
-               color_model,
-               pkg->sub_x,
-               pkg->sub_y);
-       pkg->difference2 = MotionScan::abs_diff_sub(current_ptr,
-               prev_ptr,
-               row_bytes,
-               pkg->block_x2 - pkg->block_x1,
-               pkg->block_y2 - pkg->block_y1,
-               color_model,
-               pkg->sub_x,
-               pkg->sub_y);
-// printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
-// pkg->sub_x,
-// pkg->sub_y,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->difference1,
-// pkg->difference2);
-}
 
-void MotionScanUnit::process_package(LoadPackage *package)
-{
-       MotionScanPackage *pkg = (MotionScanPackage*)package;
+
+
+
 
 
 // Single pixel
        if(!server->subpixel)
        {
-               single_pixel(pkg);
+// Try cache
+               pkg->difference1 = server->get_cache(pkg->search_x, pkg->search_y);
+               if(pkg->difference1 < 0)
+               {
+//printf("MotionScanUnit::process_package 1 search_x=%d search_y=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n", 
+//pkg->search_x, pkg->search_y, pkg->scan_x1, pkg->scan_y1, pkg->scan_x2, pkg->scan_y2, server->x_steps, server->y_steps);
+// Pointers to first pixel in each block
+                       unsigned char *prev_ptr = server->previous_frame->get_rows()[
+                               pkg->search_y] +        
+                               pkg->search_x * pixel_size;
+                       unsigned char *current_ptr = server->current_frame->get_rows()[
+                               pkg->block_y1] +
+                               pkg->block_x1 * pixel_size;
+
+// Scan block
+                       pkg->difference1 = MotionScan::abs_diff(prev_ptr,
+                               current_ptr,
+                               row_bytes,
+                               pkg->block_x2 - pkg->block_x1,
+                               pkg->block_y2 - pkg->block_y1,
+                               color_model);
+
+// printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n",
+// __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
+                       server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1);
+               }
        }
+
+
+
+
+
+
+
        else
+
+
+
+
+
+
+
+
 // Sub pixel
        {
-               subpixel(pkg);
+               unsigned char *prev_ptr = server->previous_frame->get_rows()[
+                       pkg->search_y] +
+                       pkg->search_x * pixel_size;
+               unsigned char *current_ptr = server->current_frame->get_rows()[
+                       pkg->block_y1] +
+                       pkg->block_x1 * pixel_size;
+
+// With subpixel, there are two ways to compare each position, one by shifting
+// the previous frame and two by shifting the current frame.
+               pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr,
+                       current_ptr,
+                       row_bytes,
+                       pkg->block_x2 - pkg->block_x1,
+                       pkg->block_y2 - pkg->block_y1,
+                       color_model,
+                       pkg->sub_x,
+                       pkg->sub_y);
+               pkg->difference2 = MotionScan::abs_diff_sub(current_ptr,
+                       prev_ptr,
+                       row_bytes,
+                       pkg->block_x2 - pkg->block_x1,
+                       pkg->block_y2 - pkg->block_y1,
+                       color_model,
+                       pkg->sub_x,
+                       pkg->sub_y);
+// printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
+// sub_x,
+// sub_y,
+// search_x,
+// search_y,
+// pkg->difference1,
+// pkg->difference2);
        }
 
 
@@ -191,6 +175,33 @@ void MotionScanUnit::process_package(LoadPackage *package)
 
 
 
+int64_t MotionScanUnit::get_cache(int x, int y)
+{
+       int64_t result = -1;
+       cache_lock->lock("MotionScanUnit::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               MotionScanCache *ptr = cache.values[i];
+               if(ptr->x == x && ptr->y == y)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void MotionScanUnit::put_cache(int x, int y, int64_t difference)
+{
+       MotionScanCache *ptr = new MotionScanCache(x, y, difference);
+       cache_lock->lock("MotionScanUnit::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
 
 
 
@@ -202,880 +213,135 @@ void MotionScanUnit::process_package(LoadPackage *package)
 MotionScan::MotionScan(int total_clients,
        int total_packages)
  : LoadServer(
-// DEBUG
-//1, 1
-total_clients, total_packages
+//1, 1 
+total_clients, total_packages 
 )
 {
        test_match = 1;
+       cache_lock = new Mutex("MotionScan::cache_lock");
        downsampled_previous = 0;
        downsampled_current = 0;
-       rotated_current = 0;
-       rotater = 0;
+//     downsample = 0;
 }
 
 MotionScan::~MotionScan()
 {
+       delete cache_lock;
        delete downsampled_previous;
        delete downsampled_current;
-       if(rotated_current)
-       {
-               for(int i = 0; i < total_rotated; i++)
-               {
-                       delete rotated_current[i];
-               }
-
-               delete [] rotated_current;
-       }
-       delete rotater;
+//     delete downsample;
 }
 
 
 void MotionScan::init_packages()
 {
 // Set package coords
-// Total range of positions to scan with downsampling
-       int downsampled_scan_x1 = scan_x1 / current_downsample;
-       //int downsampled_scan_x2 = scan_x2 / current_downsample;
-       int downsampled_scan_y1 = scan_y1 / current_downsample;
-       //int downsampled_scan_y2 = scan_y2 / current_downsample;
-       int downsampled_block_x1 = block_x1 / current_downsample;
-       int downsampled_block_x2 = block_x2 / current_downsample;
-       int downsampled_block_y1 = block_y1 / current_downsample;
-       int downsampled_block_y2 = block_y2 / current_downsample;
-
-
 //printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages());
-// printf("MotionScan::init_packages %d current_downsample=%d scan_x1=%d scan_x2=%d block_x1=%d block_x2=%d\n",
-// __LINE__,
-// current_downsample,
-// downsampled_scan_x1,
-// downsampled_scan_x2,
-// downsampled_block_x1,
-// downsampled_block_x2);
-// if(current_downsample == 8 && downsampled_scan_x1 == 47)
-// {
-// downsampled_previous->write_png("/tmp/previous");
-// downsampled_current->write_png("/tmp/current");
-// }
-
        for(int i = 0; i < get_total_packages(); i++)
        {
                MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
 
-               pkg->block_x1 = downsampled_block_x1;
-               pkg->block_x2 = downsampled_block_x2;
-               pkg->block_y1 = downsampled_block_y1;
-               pkg->block_y2 = downsampled_block_y2;
+               pkg->block_x1 = block_x1;
+               pkg->block_x2 = block_x2;
+               pkg->block_y1 = block_y1;
+               pkg->block_y2 = block_y2;
+               pkg->scan_x1 = scan_x1;
+               pkg->scan_x2 = scan_x2;
+               pkg->scan_y1 = scan_y1;
+               pkg->scan_y2 = scan_y2;
+               pkg->step = i;
                pkg->difference1 = 0;
                pkg->difference2 = 0;
                pkg->dx = 0;
                pkg->dy = 0;
                pkg->valid = 1;
-               pkg->angle_step = 0;
-
+               
                if(!subpixel)
                {
-                       if(rotation_pass)
-                       {
-                               pkg->search_x = scan_x1 / current_downsample;
-                               pkg->search_y = scan_y1 / current_downsample;
-                               pkg->angle_step = i;
-                       }
-                       else
-                       {
-
-                               int current_x_step = (i % x_steps);
-                               int current_y_step = (i / x_steps);
-
-       //printf("MotionScan::init_packages %d i=%d x_step=%d y_step=%d angle_step=%d\n",
-       //__LINE__, i, current_x_step, current_y_step, current_angle_step);
-                               pkg->search_x = downsampled_scan_x1 + current_x_step *
-                                       (scan_x2 - scan_x1) / current_downsample / x_steps;
-                               pkg->search_y = downsampled_scan_y1 + current_y_step *
-                                       (scan_y2 - scan_y1) / current_downsample / y_steps;
-
-                               if(do_rotate)
-                               {
-                                       pkg->angle_step = angle_steps / 2;
-                               }
-                               else
-                               {
-                                       pkg->angle_step = 0;
-                               }
-                       }
-
+                       pkg->search_x = pkg->scan_x1 + (pkg->step % x_steps) *
+                               (scan_x2 - scan_x1) / x_steps;
+                       pkg->search_y = pkg->scan_y1 + (pkg->step / x_steps) *
+                               (scan_y2 - scan_y1) / y_steps;
                        pkg->sub_x = 0;
                        pkg->sub_y = 0;
                }
                else
                {
-                       pkg->sub_x = i % (OVERSAMPLE * SUBPIXEL_RANGE);
-                       pkg->sub_y = i / (OVERSAMPLE * SUBPIXEL_RANGE);
-
-//                     if(horizontal_only)
-//                     {
-//                             pkg->sub_y = 0;
-//                     }
-//
-//                     if(vertical_only)
-//                     {
-//                             pkg->sub_x = 0;
-//                     }
-
-                       pkg->search_x = scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
-                       pkg->search_y = scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
-                       pkg->sub_x %= OVERSAMPLE;
-                       pkg->sub_y %= OVERSAMPLE;
-
-
-
-// printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n",
-// __LINE__,
-// i,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->sub_x,
-// pkg->sub_y);
-               }
-
-// printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
-// __LINE__,
-// scan_x1,
-// scan_x2,
-// scan_y1,
-// scan_y2,
-// pkg->search_x,
-// pkg->search_y);
-       }
-}
-
-LoadClient* MotionScan::new_client()
-{
-       return new MotionScanUnit(this);
-}
-
-LoadPackage* MotionScan::new_package()
-{
-       return new MotionScanPackage;
-}
-
-
-void MotionScan::set_test_match(int value)
-{
-       this->test_match = value;
-}
-
-
-
-
-#define DOWNSAMPLE(type, temp_type, components, max) \
-{ \
-       temp_type r; \
-       temp_type g; \
-       temp_type b; \
-       temp_type a; \
-       type **in_rows = (type**)src->get_rows(); \
-       type **out_rows = (type**)dst->get_rows(); \
- \
-       for(int i = 0; i < h; i += downsample) \
-       { \
-               int y1 = MAX(i, 0); \
-               int y2 = MIN(i + downsample, h); \
- \
- \
-               for(int j = 0; \
-                       j < w; \
-                       j += downsample) \
-               { \
-                       int x1 = MAX(j, 0); \
-                       int x2 = MIN(j + downsample, w); \
- \
-                       temp_type scale = (x2 - x1) * (y2 - y1); \
-                       if(x2 > x1 && y2 > y1) \
-                       { \
- \
-/* Read in values */ \
-                               r = 0; \
-                               g = 0; \
-                               b = 0; \
-                               if(components == 4) a = 0; \
- \
-                               for(int k = y1; k < y2; k++) \
-                               { \
-                                       type *row = in_rows[k] + x1 * components; \
-                                       for(int l = x1; l < x2; l++) \
-                                       { \
-                                               r += *row++; \
-                                               g += *row++; \
-                                               b += *row++; \
-                                               if(components == 4) a += *row++; \
-                                       } \
-                               } \
- \
-/* Write average */ \
-                               r /= scale; \
-                               g /= scale; \
-                               b /= scale; \
-                               if(components == 4) a /= scale; \
- \
-                               type *row = out_rows[y1 / downsample] + \
-                                       x1 / downsample * components; \
-                               *row++ = r; \
-                               *row++ = g; \
-                               *row++ = b; \
-                               if(components == 4) *row++ = a; \
-                       } \
-               } \
-/*printf("DOWNSAMPLE 3 %d\n", i);*/ \
-       } \
-}
-
-
-
-
-void MotionScan::downsample_frame(VFrame *dst,
-       VFrame *src,
-       int downsample)
-{
-       int h = src->get_h();
-       int w = src->get_w();
-
-//PRINT_TRACE
-//printf("downsample=%d w=%d h=%d dst=%d %d\n", downsample, w, h, dst->get_w(), dst->get_h());
-       switch(src->get_color_model())
-       {
-               case BC_RGB888:
-                       DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
-                       break;
-               case BC_RGB_FLOAT:
-                       DOWNSAMPLE(float, float, 3, 1.0)
-                       break;
-               case BC_RGBA8888:
-                       DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
-                       break;
-               case BC_RGBA_FLOAT:
-                       DOWNSAMPLE(float, float, 4, 1.0)
-                       break;
-               case BC_YUV888:
-                       DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
-                       break;
-               case BC_YUVA8888:
-                       DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
-                       break;
-       }
-//PRINT_TRACE
-}
+                       pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
+                       pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
 
-double MotionScan::step_to_angle(int step, double center)
-{
-       if(step < angle_steps / 2)
-       {
-               return center - angle_step * (angle_steps / 2 - step);
-       }
-       else
-       if(step > angle_steps / 2)
-       {
-               return center + angle_step * (step - angle_steps / 2);
-       }
-       else
-       {
-               return center;
-       }
-}
-
-#ifdef STDDEV_TEST
-static int compare(const void *p1, const void *p2)
-{
-       double value1 = *(double*)p1;
-       double value2 = *(double*)p2;
-
-//printf("compare %d value1=%f value2=%f\n", __LINE__, value1, value2);
-       return value1 > value2;
-}
-#endif
-
-// reject vectors based on content.  It's the reason Goog can't stabilize timelapses.
-//#define STDDEV_TEST
-
-// pixel accurate motion search
-void MotionScan::pixel_search(int &x_result, int &y_result, double &r_result)
-{
-// reduce level of detail until enough steps
-       while(current_downsample > 1 &&
-               ((block_x2 - block_x1) / current_downsample < MIN_DOWNSAMPLED_SIZE ||
-               (block_y2 - block_y1) / current_downsample < MIN_DOWNSAMPLED_SIZE
-               ||
-                (scan_x2 - scan_x1) / current_downsample < MIN_DOWNSAMPLED_SCAN ||
-               (scan_y2 - scan_y1) / current_downsample < MIN_DOWNSAMPLED_SCAN
-               ))
-       {
-               current_downsample /= 2;
-       }
-
-
-
-// create downsampled images.
-// Need to keep entire frame to search for rotation.
-       int downsampled_prev_w = previous_frame_arg->get_w() / current_downsample;
-       int downsampled_prev_h = previous_frame_arg->get_h() / current_downsample;
-       int downsampled_current_w = current_frame_arg->get_w() / current_downsample;
-       int downsampled_current_h = current_frame_arg->get_h() / current_downsample;
-
-// printf("MotionScan::pixel_search %d current_downsample=%d current_frame_arg->get_w()=%d downsampled_current_w=%d\n",
-// __LINE__,
-// current_downsample,
-// current_frame_arg->get_w(),
-// downsampled_current_w);
-
-       x_steps = (scan_x2 - scan_x1) / current_downsample;
-       y_steps = (scan_y2 - scan_y1) / current_downsample;
-
-// in rads
-       double test_angle1 = atan2((double)downsampled_current_h / 2 - 1, (double)downsampled_current_w / 2);
-       double test_angle2 = atan2((double)downsampled_current_h / 2, (double)downsampled_current_w / 2 - 1);
-
-// in deg
-       angle_step = 360.0f * fabs(test_angle1 - test_angle2) / 2 / M_PI;
-
-// printf("MotionScan::pixel_search %d test_angle1=%f test_angle2=%f angle_step=%f\n",
-// __LINE__,
-// 360.0f * test_angle1 / 2 / M_PI,
-// 360.0f * test_angle2 / 2 / M_PI,
-// angle_step);
-
-
-       if(do_rotate && angle_step < rotation_range)
-       {
-               angle_steps = 1 + (int)((scan_angle2 - scan_angle1) / angle_step + 0.5);
-       }
-       else
-       {
-               angle_steps = 1;
-       }
-
-
-       if(current_downsample > 1)
-       {
-               if(!downsampled_previous ||
-                       downsampled_previous->get_w() != downsampled_prev_w ||
-                       downsampled_previous->get_h() != downsampled_prev_h)
-               {
-                       delete downsampled_previous;
-                       downsampled_previous = new VFrame();
-                       downsampled_previous->set_use_shm(0);
-                       downsampled_previous->reallocate(0,
-                               -1,
-                               0,
-                               0,
-                               0,
-                               downsampled_prev_w + 1,
-                               downsampled_prev_h + 1,
-                               previous_frame_arg->get_color_model(),
-                               -1);
-               }
-
-               if(!downsampled_current ||
-                       downsampled_current->get_w() != downsampled_current_w ||
-                       downsampled_current->get_h() != downsampled_current_h)
-               {
-                       delete downsampled_current;
-                       downsampled_current = new VFrame();
-                       downsampled_current->set_use_shm(0);
-                       downsampled_current->reallocate(0,
-                               -1,
-                               0,
-                               0,
-                               0,
-                               downsampled_current_w + 1,
-                               downsampled_current_h + 1,
-                               current_frame_arg->get_color_model(),
-                               -1);
-               }
-
-
-               downsample_frame(downsampled_previous,
-                       previous_frame_arg,
-                       current_downsample);
-               downsample_frame(downsampled_current,
-                       current_frame_arg,
-                       current_downsample);
-               previous_frame = downsampled_previous;
-               current_frame = downsampled_current;
-
-       }
-       else
-       {
-               previous_frame = previous_frame_arg;
-               current_frame = current_frame_arg;
-       }
-
-
-
-// printf("MotionScan::pixel_search %d x_steps=%d y_steps=%d angle_steps=%d total_steps=%d\n",
-// __LINE__,
-// x_steps,
-// y_steps,
-// angle_steps,
-// total_steps);
-
-
-
-// test variance of constant macroblock
-       int color_model = current_frame->get_color_model();
-       int pixel_size = BC_CModels::calculate_pixelsize(color_model);
-       int row_bytes = current_frame->get_bytes_per_line();
-       int block_w = block_x2 - block_x1;
-       int block_h = block_y2 - block_y1;
-
-       unsigned char *current_ptr =
-               current_frame->get_rows()[block_y1 / current_downsample] +
-               (block_x1 / current_downsample) * pixel_size;
-       unsigned char *previous_ptr =
-               previous_frame->get_rows()[scan_y1 / current_downsample] +
-               (scan_x1 / current_downsample) * pixel_size;
-
-
-
-// test detail in prev & current frame
-       double range1 = calculate_range(current_ptr,
-               row_bytes,
-               block_w / current_downsample,
-               block_h / current_downsample,
-               color_model);
-
-       if(range1 < 1)
-       {
-printf("MotionScan::pixel_search %d range fail range1=%f\n", __LINE__, range1);
-               failed = 1;
-               return;
-       }
-
-       double range2 = calculate_range(previous_ptr,
-               row_bytes,
-               block_w / current_downsample,
-               block_h / current_downsample,
-               color_model);
-
-       if(range2 < 1)
-       {
-printf("MotionScan::pixel_search %d range fail range2=%f\n", __LINE__, range2);
-               failed = 1;
-               return;
-       }
-
-
-// create rotated images
-       if(rotated_current &&
-               (total_rotated != angle_steps ||
-               rotated_current[0]->get_w() != downsampled_current_w ||
-               rotated_current[0]->get_h() != downsampled_current_h))
-       {
-               for(int i = 0; i < total_rotated; i++)
-               {
-                       delete rotated_current[i];
-               }
-
-               delete [] rotated_current;
-               rotated_current = 0;
-               total_rotated = 0;
-       }
-
-       if(do_rotate)
-       {
-               total_rotated = angle_steps;
-
-
-               if(!rotated_current)
-               {
-                       rotated_current = new VFrame*[total_rotated];
-                       bzero(rotated_current, sizeof(VFrame*) * total_rotated);
-               }
-
-// printf("MotionScan::pixel_search %d total_rotated=%d w=%d h=%d block_w=%d block_h=%d\n",
-// __LINE__,
-// total_rotated,
-// downsampled_current_w,
-// downsampled_current_h,
-// (block_x2 - block_x1) / current_downsample,
-// (block_y2 - block_y1) / current_downsample);
-               for(int i = 0; i < angle_steps; i++)
-               {
-
-// printf("MotionScan::pixel_search %d w=%d h=%d x=%d y=%d angle=%f\n",
-// __LINE__,
-// downsampled_current_w,
-// downsampled_current_h,
-// (block_x1 + block_x2) / 2 / current_downsample,
-// (block_y1 + block_y2) / 2 / current_downsample,
-// step_to_angle(i, r_result));
-
-// printf("MotionScan::pixel_search %d i=%d rotated_current[i]=%p\n",
-// __LINE__,
-// i,
-// rotated_current[i]);
-                       if(!rotated_current[i])
+                       if(horizontal_only)
                        {
-                               rotated_current[i] = new VFrame();
-                               rotated_current[i]->set_use_shm(0);
-                               rotated_current[i]->reallocate(0,
-                                       -1,
-                                       0,
-                                       0,
-                                       0,
-                                       downsampled_current_w + 1,
-                                       downsampled_current_h + 1,
-                                       current_frame_arg->get_color_model(),
-                                       -1);
-//printf("MotionScan::pixel_search %d\n", __LINE__);
+                               pkg->sub_y = 0;
                        }
 
-
-                       if(!rotater)
+                       if(vertical_only)
                        {
-                               rotater = new AffineEngine(get_total_clients(),
-                                       get_total_clients());
+                               pkg->sub_x = 0;
                        }
 
-// get smallest viewport size required for the angle
-                       double diag = hypot((block_x2 - block_x1) / current_downsample,
-                               (block_y2 - block_y1) / current_downsample);
-                       double angle1 = atan2(block_y2 - block_y1, block_x2 - block_x1) +
-                               TO_RAD(step_to_angle(i, r_result));
-                       double angle2 = -atan2(block_y2 - block_y1, block_x2 - block_x1) +
-                               TO_RAD(step_to_angle(i, r_result));
-                       double max_horiz = MAX(abs(diag * cos(angle1)), abs(diag * cos(angle2)));
-                       double max_vert = MAX(abs(diag * sin(angle1)), abs(diag * sin(angle2)));
-                       int center_x = (block_x1 + block_x2) / 2 / current_downsample;
-                       int center_y = (block_y1 + block_y2) / 2 / current_downsample;
-                       int x1 = center_x - max_horiz / 2;
-                       int y1 = center_y - max_vert / 2;
-                       int x2 = x1 + max_horiz;
-                       int y2 = y1 + max_vert;
-                       CLAMP(x1, 0, downsampled_current_w - 1);
-                       CLAMP(y1, 0, downsampled_current_h - 1);
-                       CLAMP(x2, 0, downsampled_current_w - 1);
-                       CLAMP(y2, 0, downsampled_current_h - 1);
-
-//printf("MotionScan::pixel_search %d %f %f %d %d\n",
-//__LINE__, TO_DEG(angle1), TO_DEG(angle2), (int)max_horiz, (int)max_vert);
-                       rotater->set_in_viewport(x1,
-                               y1,
-                               x2 - x1,
-                               y2 - y1);
-                       rotater->set_out_viewport(x1,
-                               y1,
-                               x2 - x1,
-                               y2 - y1);
-
-//                     rotater->set_in_viewport(0,
-//                             0,
-//                             downsampled_current_w,
-//                             downsampled_current_h);
-//                     rotater->set_out_viewport(0,
-//                             0,
-//                             downsampled_current_w,
-//                             downsampled_current_h);
-
-                       rotater->set_in_pivot(center_x, center_y);
-                       rotater->set_out_pivot(center_x, center_y);
-
-                       rotater->rotate(rotated_current[i],
-                               current_frame,
-                               step_to_angle(i, r_result));
-
-// rotated_current[i]->draw_rect(block_x1 / current_downsample,
-// block_y1 / current_downsample,
-// block_x2 / current_downsample,
-// block_y2 / current_downsample);
-// char string[BCTEXTLEN];
-// sprintf(string, "/tmp/rotated%d", i);
-// rotated_current[i]->write_png(string);
-//downsampled_previous->write_png("/tmp/previous");
-//printf("MotionScan::pixel_search %d\n", __LINE__);
-               }
-       }
-
-
-
-
-
-
-// printf("MotionScan::pixel_search %d block x=%d y=%d w=%d h=%d\n",
-// __LINE__,
-// block_x1 / current_downsample,
-// block_y1 / current_downsample,
-// block_w / current_downsample,
-// block_h / current_downsample);
-
-
-
-
-
-
-
-//exit(1);
-// Test only translation of the middle rotated frame
-       rotation_pass = 0;
-       total_steps = x_steps * y_steps;
-       set_package_count(total_steps);
-       process_packages();
-
-
-
-
-
-
-// Get least difference
-       int64_t min_difference = -1;
-#ifdef STDDEV_TEST
-       double stddev_table[get_total_packages()];
-#endif
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-
-#ifdef STDDEV_TEST
-               double stddev = sqrt(pkg->difference1) /
-                       (block_w / current_downsample) /
-                       (block_h / current_downsample) /
-                       3;
-// printf("MotionScan::pixel_search %d current_downsample=%d search_x=%d search_y=%d diff1=%f\n",
-// __LINE__,
-// current_downsample,
-// pkg->search_x,
-// pkg->search_y,
-// sqrt(pkg->difference1) / block_w / current_downsample / block_h / 3 /* / variance */);
-
-// printf("MotionScan::pixel_search %d range1=%f stddev=%f\n",
-// __LINE__,
-// range1,
-// stddev);
-
-               stddev_table[i] = stddev;
-#endif // STDDEV_TEST
-
-               if(pkg->difference1 < min_difference || i == 0)
-               {
-                       min_difference = pkg->difference1;
-                       x_result = pkg->search_x * current_downsample * OVERSAMPLE;
-                       y_result = pkg->search_y * current_downsample * OVERSAMPLE;
-
-// printf("MotionScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
-// __LINE__,
-// block_x1 * OVERSAMPLE - x_result,
-// block_y1 * OVERSAMPLE - y_result,
-// pkg->angle_step,
-// pkg->difference1);
-
-               }
-       }
-
-
-#ifdef STDDEV_TEST
-       qsort(stddev_table, get_total_packages(), sizeof(double), compare);
-
-
-// reject motion vector if not similar enough
-//     if(stddev_table[0] > 0.2)
-//     {
-// if(debug)
-// {
-// printf("MotionScan::pixel_search %d stddev fail min_stddev=%f\n",
-// __LINE__,
-// stddev_table[0]);
-// }
-//             failed = 1;
-//             return;
-//     }
-
-if(debug)
-{
-       printf("MotionScan::pixel_search %d\n", __LINE__);
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               printf("%f\n", stddev_table[i]);
-       }
-}
-
-// reject motion vector if not a sigmoid curve
-// TODO: use linear interpolation
-       int steps = 2;
-       int step = get_total_packages() / steps;
-       double curve[steps];
-       for(int i = 0; i < steps; i++)
-       {
-               int start = get_total_packages() * i / steps;
-               int end = get_total_packages() * (i + 1) / steps;
-               end = MIN(end, get_total_packages() - 1);
-               curve[i] = stddev_table[end] - stddev_table[start];
-       }
-
-
-//     if(curve[0] < (curve[1] * 1.01) ||
-//             curve[2] < (curve[1] * 1.01) ||
-//             curve[0] < (curve[2] * 0.75))
-//     if(curve[0] < curve[1])
-//     {
-// if(debug)
-// {
-// printf("MotionScan::pixel_search %d curve fail %f %f\n",
-// __LINE__,
-// curve[0],
-// curve[1]);
-// }
-//             failed = 1;
-//             return;
-//     }
-
-if(debug)
-{
-printf("MotionScan::pixel_search %d curve=%f %f ranges=%f %f min_stddev=%f\n",
-__LINE__,
-curve[0],
-curve[1],
-range1,
-range2,
-stddev_table[0]);
-}
-#endif // STDDEV_TEST
-
-
-
-
-
-       if(do_rotate)
-       {
-               rotation_pass = 1;;
-               total_steps = angle_steps;
-               scan_x1 = x_result / OVERSAMPLE;
-               scan_y1 = y_result / OVERSAMPLE;
-               set_package_count(total_steps);
-               process_packages();
-
+                       pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
+                       pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
+                       pkg->sub_x %= OVERSAMPLE;
+                       pkg->sub_y %= OVERSAMPLE;
 
 
-               min_difference = -1;
-               double prev_r_result = r_result;
-               for(int i = 0; i < get_total_packages(); i++)
-               {
-                       MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
 
-// printf("MotionScan::pixel_search %d search_x=%d search_y=%d angle_step=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
+// printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n", 
 // __LINE__,
+// i,
 // pkg->search_x,
 // pkg->search_y,
-// pkg->search_angle_step,
 // pkg->sub_x,
-// pkg->sub_y,
-// pkg->difference1,
-// pkg->difference2);
-                       if(pkg->difference1 < min_difference || i == 0)
-                       {
-                               min_difference = pkg->difference1;
-                               r_result = step_to_angle(i, prev_r_result);
-
-       // printf("MotionScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
-       // __LINE__,
-       // block_x1 * OVERSAMPLE - x_result,
-       // block_y1 * OVERSAMPLE - y_result,
-       // pkg->angle_step,
-       // pkg->difference1);
-                       }
+// pkg->sub_y);
                }
-       }
 
-
-// printf("MotionScan::scan_frame %d current_downsample=%d x_result=%f y_result=%f r_result=%f\n",
+// printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
 // __LINE__,
-// current_downsample,
-// (float)x_result / OVERSAMPLE,
-// (float)y_result / OVERSAMPLE,
-// r_result);
-
-}
-
-
-// subpixel motion search
-void MotionScan::subpixel_search(int &x_result, int &y_result)
-{
-       rotation_pass = 0;
-       previous_frame = previous_frame_arg;
-       current_frame = current_frame_arg;
-
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
-// Scan every subpixel in a SUBPIXEL_RANGE * SUBPIXEL_RANGE square
-       total_steps = (SUBPIXEL_RANGE * OVERSAMPLE) * (SUBPIXEL_RANGE * OVERSAMPLE);
-
-// These aren't used in subpixel
-       x_steps = OVERSAMPLE * SUBPIXEL_RANGE;
-       y_steps = OVERSAMPLE * SUBPIXEL_RANGE;
-       angle_steps = 1;
-
-       set_package_count(this->total_steps);
-       process_packages();
-
-// Get least difference
-       int64_t min_difference = -1;
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-//printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
-//__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
-               if(pkg->difference1 < min_difference || min_difference == -1)
-               {
-                       min_difference = pkg->difference1;
-
-// The sub coords are 1 pixel up & left of the block coords
-                       x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
-                       y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
-
+// scan_x1,
+// scan_x2,
+// scan_y1,
+// scan_y2,
+// pkg->search_x,
+// pkg->search_y);
+       }
+}
 
-// Fill in results
-                       dx_result = block_x1 * OVERSAMPLE - x_result;
-                       dy_result = block_y1 * OVERSAMPLE - y_result;
-//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
-//__LINE__, dx_result, dy_result, min_difference);
-               }
+LoadClient* MotionScan::new_client()
+{
+       return new MotionScanUnit(this);
+}
 
-               if(pkg->difference2 < min_difference)
-               {
-                       min_difference = pkg->difference2;
+LoadPackage* MotionScan::new_package()
+{
+       return new MotionScanPackage;
+}
 
-                       x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x;
-                       y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y;
 
-                       dx_result = block_x1 * OVERSAMPLE - x_result;
-                       dy_result = block_y1 * OVERSAMPLE - y_result;
-//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n",
-//__LINE__, dx_result, dy_result, min_difference);
-               }
-       }
+void MotionScan::set_test_match(int value)
+{
+       this->test_match = value;
 }
 
-
 void MotionScan::scan_frame(VFrame *previous_frame,
        VFrame *current_frame,
        int global_range_w,
        int global_range_h,
        int global_block_w,
        int global_block_h,
-       int block_x,
-       int block_y,
+       double block_x,
+       double block_y,
        int frame_type,
        int tracking_type,
        int action_type,
        int horizontal_only,
        int vertical_only,
        int source_position,
+       int total_steps,
        int total_dx,
        int total_dy,
        int global_origin_x,
-       int global_origin_y,
-       int do_motion,
-       int do_rotate,
-       double rotation_center,
-       double rotation_range)
+       int global_origin_y)
 {
        this->previous_frame_arg = previous_frame;
        this->current_frame_arg = current_frame;
@@ -1085,51 +351,25 @@ void MotionScan::scan_frame(VFrame *previous_frame,
        this->current_frame = current_frame_arg;
        this->global_origin_x = global_origin_x;
        this->global_origin_y = global_origin_y;
-       this->action_type = action_type;
-       this->do_motion = do_motion;
-       this->do_rotate = do_rotate;
-       this->rotation_center = rotation_center;
-       this->rotation_range = rotation_range;
-
-//printf("MotionScan::scan_frame %d\n", __LINE__);
-       dx_result = 0;
-       dy_result = 0;
-       dr_result = 0;
-       failed = 0;
-
        subpixel = 0;
-// starting level of detail
-// TODO: base it on a table of resolutions
-       current_downsample = STARTING_DOWNSAMPLE;
-       angle_step = 0;
+
+       cache.remove_all_objects();
 
 // Single macroblock
        int w = current_frame->get_w();
        int h = current_frame->get_h();
 
 // Initial search parameters
-       scan_w = global_range_w;
-       scan_h = global_range_h;
-
-       int block_w = global_block_w;
-       int block_h = global_block_h;
-
-// printf("MotionScan::scan_frame %d %d %d %d %d %d %d %d %d\n",
-// __LINE__,
-// global_range_w,
-// global_range_h,
-// global_block_w,
-// global_block_h,
-// scan_w,
-// scan_h,
-// block_w,
-// block_h);
+       int scan_w = w * global_range_w / 100;
+       int scan_h = h * global_range_h / 100;
+       int block_w = w * global_block_w / 100;
+       int block_h = h * global_block_h / 100;
 
 // Location of block in previous frame
-       block_x1 = (int)(block_x - block_w / 2);
-       block_y1 = (int)(block_y - block_h / 2);
-       block_x2 = (int)(block_x + block_w / 2);
-       block_y2 = (int)(block_y + block_h / 2);
+       block_x1 = (int)(w * block_x / 100 - block_w / 2);
+       block_y1 = (int)(h * block_y / 100 - block_h / 2);
+       block_x2 = (int)(w * block_x / 100 + block_w / 2);
+       block_y2 = (int)(h * block_y / 100 + block_h / 2);
 
 // Offset to location of previous block.  This offset needn't be very accurate
 // since it's the offset of the previous image and current image we want.
@@ -1149,7 +389,6 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                case MotionScan::NO_CALCULATE:
                        dx_result = 0;
                        dy_result = 0;
-                       dr_result = rotation_center;
                        skip = 1;
                        break;
 
@@ -1157,55 +396,21 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                {
 // Load result from disk
                        char string[BCTEXTLEN];
-
-                       skip = 1;
-                       if(do_motion)
-                       {
-                               sprintf(string, "%s%06d",
-                                       MOTION_FILE,
-                                       source_position);
+                       sprintf(string, "%s%06d", 
+                               MOTION_FILE, 
+                               source_position);
 //printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
-                               FILE *input = fopen(string, "r");
-                               if(input)
-                               {
-                                       int temp = fscanf(input,
-                                               "%d %d",
-                                               &dx_result,
-                                               &dy_result);
-                                       if( temp != 2 )
-                                               printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
+                       FILE *input = fopen(string, "r");
+                       if(input)
+                       {
+                               (void)fscanf(input, "%d %d", 
+                                       &dx_result, &dy_result);
 // HACK
 //dx_result *= 2;
 //dy_result *= 2;
 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
-                                       fclose(input);
-                               }
-                               else
-                               {
-                                       skip = 0;
-                               }
-                       }
-
-                       if(do_rotate)
-                       {
-                               sprintf(string,
-                                       "%s%06d",
-                                       ROTATION_FILE,
-                                       source_position);
-                               FILE *input = fopen(string, "r");
-                               if(input)
-                               {
-                                       int temp = fscanf(input, "%f", &dr_result);
-                                       if( temp != 1 )
-                                               printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
-// DEBUG
-//dr_result += 0.25;
-                                       fclose(input);
-                               }
-                               else
-                               {
-                                       skip = 0;
-                               }
+                               fclose(input);
+                               skip = 1;
                        }
                        break;
                }
@@ -1216,8 +421,6 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                        break;
        }
 
-
-
        if(!skip && test_match)
        {
                if(previous_frame->data_matches(current_frame))
@@ -1225,21 +428,19 @@ void MotionScan::scan_frame(VFrame *previous_frame,
 printf("MotionScan::scan_frame: data matches. skipping.\n");
                        dx_result = 0;
                        dy_result = 0;
-                       dr_result = rotation_center;
                        skip = 1;
                }
        }
 
-
 // Perform scan
        if(!skip)
        {
+//printf("MotionScan::scan_frame %d\n", __LINE__);
 // Location of block in current frame
-               int origin_offset_x = this->global_origin_x;
-               int origin_offset_y = this->global_origin_y;
+               int origin_offset_x = this->global_origin_x * w / 100;
+               int origin_offset_y = this->global_origin_y * h / 100;
                int x_result = block_x1 + origin_offset_x;
                int y_result = block_y1 + origin_offset_y;
-               double r_result = rotation_center;
 
 // printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
 // block_x1 + block_w / 2,
@@ -1251,31 +452,32 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // block_x2,
 // block_y2);
 
-               while(!failed)
+               while(1)
                {
+// Cache needs to be cleared if downsampling is used because the sums of 
+// different downsamplings can't be compared.
+// Subpixel never uses the cache.
+//                     cache.remove_all_objects();
                        scan_x1 = x_result - scan_w / 2;
                        scan_y1 = y_result - scan_h / 2;
                        scan_x2 = x_result + scan_w / 2;
                        scan_y2 = y_result + scan_h / 2;
-                       scan_angle1 = r_result - rotation_range;
-                       scan_angle2 = r_result + rotation_range;
 
 
 
 // Zero out requested values
-//                     if(horizontal_only)
-//                     {
-//                             scan_y1 = block_y1;
-//                             scan_y2 = block_y1 + 1;
-//                     }
-//                     if(vertical_only)
-//                     {
-//                             scan_x1 = block_x1;
-//                             scan_x2 = block_x1 + 1;
-//                     }
-
-// printf("MotionScan::scan_frame %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n",
-// __LINE__,
+                       if(horizontal_only)
+                       {
+                               scan_y1 = block_y1;
+                               scan_y2 = block_y1 + 1;
+                       }
+                       if(vertical_only)
+                       {
+                               scan_x1 = block_x1;
+                               scan_x2 = block_x1 + 1;
+                       }
+
+// printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
 // block_x1,
 // block_y1,
 // block_x2,
@@ -1284,11 +486,9 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // scan_y1,
 // scan_x2,
 // scan_y2);
-
-
 // Clamp the block coords before the scan so we get useful scan coords.
-                       clamp_scan(w,
-                               h,
+                       clamp_scan(w, 
+                               h, 
                                &block_x1,
                                &block_y1,
                                &block_x2,
@@ -1298,21 +498,18 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                                &scan_x2,
                                &scan_y2,
                                0);
-
-
-// printf("MotionScan::scan_frame %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_result=%d y_result=%d\n",
+// printf("MotionScan::scan_frame 1 %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n        scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n    x_result=%d y_result=%d\n", 
 // __LINE__,
 // block_x1,
 // block_y1,
 // block_x2,
 // block_y2,
-// scan_x1,
-// scan_y1,
-// scan_x2,
-// scan_y2,
-// x_result,
+// scan_x1, 
+// scan_y1, 
+// scan_x2, 
+// scan_y2, 
+// x_result, 
 // y_result);
-//if(y_result == 88) exit(0);
 
 
 // Give up if invalid coords.
@@ -1320,49 +517,179 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                                scan_x2 <= scan_x1 ||
                                block_x2 <= block_x1 ||
                                block_y2 <= block_y1)
-                       {
                                break;
-                       }
 
 // For subpixel, the top row and left column are skipped
                        if(subpixel)
                        {
 
-                               subpixel_search(x_result, y_result);
-// printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n",
-// __LINE__,
-// x_result / OVERSAMPLE,
-// y_result / OVERSAMPLE);
+//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
+// Scan every subpixel in a 2 pixel * 2 pixel square
+                               total_pixels = (2 * OVERSAMPLE) * (2 * OVERSAMPLE);
+
+                               this->total_steps = total_pixels;
+// These aren't used in subpixel
+                               this->x_steps = OVERSAMPLE * 2;
+                               this->y_steps = OVERSAMPLE * 2;
+
+                               set_package_count(this->total_steps);
+                               process_packages();
+
+// Get least difference
+                               int64_t min_difference = -1;
+                               for(int i = 0; i < get_total_packages(); i++)
+                               {
+                                       MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
+//printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", 
+//__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
+                                       if(pkg->difference1 < min_difference || min_difference == -1)
+                                       {
+                                               min_difference = pkg->difference1;
+
+// The sub coords are 1 pixel up & left of the block coords
+                                               x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
+                                               y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
+
+
+// Fill in results
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", 
+//__LINE__, dx_result, dy_result, min_difference);
+                                       }
+
+                                       if(pkg->difference2 < min_difference)
+                                       {
+                                               min_difference = pkg->difference2;
+
+                                               x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x;
+                                               y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y;
+
+                                               dx_result = block_x1 * OVERSAMPLE - x_result;
+                                               dy_result = block_y1 * OVERSAMPLE - y_result;
+//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", 
+//__LINE__, dx_result, dy_result, min_difference);
+                                       }
+                               }
 
                                break;
                        }
                        else
 // Single pixel
                        {
-                               pixel_search(x_result, y_result, r_result);
-//printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result / OVERSAMPLE, y_result / OVERSAMPLE);
+                               total_pixels = (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
+                               this->total_steps = MIN(total_steps, total_pixels);
 
-                               if(failed)
+                               if(this->total_steps == total_pixels)
                                {
-                                       dr_result = 0;
-                                       dx_result = 0;
-                                       dy_result = 0;
+                                       x_steps = scan_x2 - scan_x1;
+                                       y_steps = scan_y2 - scan_y1;
                                }
                                else
-                               if(current_downsample <= 1)
                                {
-                       // Single pixel accuracy reached.  Now do exhaustive subpixel search.
+                                       x_steps = (int)sqrt(this->total_steps);
+                                       y_steps = (int)sqrt(this->total_steps);
+                               }
+
+// Use downsampled images
+//                             if(scan_x2 - scan_x1 > x_steps * 4 ||
+//                                     scan_y2 - scan_y1 > y_steps * 4)
+//                             {
+// printf("MotionScan::scan_frame %d total_pixels=%d total_steps=%d x_steps=%d y_steps=%d x y steps=%d\n",
+// __LINE__,
+// total_pixels,
+// total_steps,
+// x_steps,
+// y_steps,
+// x_steps * y_steps);
+// 
+//                                     if(!downsampled_previous ||
+//                                             !downsampled_previous->equivalent(previous_frame_arg))
+//                                     {
+//                                             delete downsampled_previous;
+//                                             downsampled_previous = new VFrame(*previous_frame_arg);
+//                                     }
+// 
+//                                     if(!downsampled_current ||
+//                                             !downsampled_current->equivalent(current_frame_arg))
+//                                     {
+//                                             delete downsampled_current;
+//                                             downsampled_current = new VFrame(*current_frame_arg);
+//                                     }
+// 
+// 
+//                                     if(!downsample)
+//                                             downsample = new DownSampleServer(get_total_clients(), 
+//                                                     get_total_clients());
+//                                     downsample->process_frame(downsampled_previous, 
+//                                             previous_frame_arg, 
+//                                             1, 
+//                                             1, 
+//                                             1, 
+//                                             1,
+//                                             (scan_y2 - scan_y1) / y_steps,
+//                                             (scan_x2 - scan_x1) / x_steps,
+//                                             0,
+//                                             0);
+//                                     downsample->process_frame(downsampled_current, 
+//                                             current_frame_arg, 
+//                                             1, 
+//                                             1, 
+//                                             1, 
+//                                             1,
+//                                             (scan_y2 - scan_y1) / y_steps,
+//                                             (scan_x2 - scan_x1) / x_steps,
+//                                             0,
+//                                             0);
+//                                     this->previous_frame = downsampled_previous;
+//                                     this->current_frame = downsampled_current;
+//                             }
+
+
+
+
+
+// printf("MotionScan::scan_frame %d this->total_steps=%d\n", 
+// __LINE__, 
+// this->total_steps);
+
+
+                               set_package_count(this->total_steps);
+                               process_packages();
+
+// Get least difference
+                               int64_t min_difference = -1;
+                               for(int i = 0; i < get_total_packages(); i++)
+                               {
+                                       MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
+//printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", 
+//__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2);
+                                       if(pkg->difference1 < min_difference || min_difference == -1)
+                                       {
+                                               min_difference = pkg->difference1;
+                                               x_result = pkg->search_x;
+                                               y_result = pkg->search_y;
+                                               x_result *= OVERSAMPLE;
+                                               y_result *= OVERSAMPLE;
+//printf("MotionScan::scan_frame %d x_result=%d y_result=%d diff=%lld\n", 
+//__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, pkg->difference1);
+                                       }
+                               }
+
+
+// If a new search is required, rescale results back to pixels.
+                               if(this->total_steps >= total_pixels)
+                               {
+// Single pixel accuracy reached.  Now do exhaustive subpixel search.
                                        if(action_type == MotionScan::STABILIZE ||
                                                action_type == MotionScan::TRACK ||
                                                action_type == MotionScan::NOTHING)
                                        {
+//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
                                                x_result /= OVERSAMPLE;
                                                y_result /= OVERSAMPLE;
-//printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result, y_result);
-                                               scan_w = SUBPIXEL_RANGE;
-                                               scan_h = SUBPIXEL_RANGE;
-// Final R result
-                                               dr_result = rotation_center - r_result;
+                                               scan_w = 2;
+                                               scan_h = 2;
                                                subpixel = 1;
                                        }
                                        else
@@ -1370,109 +697,59 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // Fill in results and quit
                                                dx_result = block_x1 * OVERSAMPLE - x_result;
                                                dy_result = block_y1 * OVERSAMPLE - y_result;
-                                               dr_result = rotation_center - r_result;
+//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
                                                break;
                                        }
                                }
                                else
 // Reduce scan area and try again
                                {
-//                                     scan_w = (scan_x2 - scan_x1) / 2;
-//                                     scan_h = (scan_y2 - scan_y1) / 2;
-// need slightly more than 2x downsampling factor
-
-                                       if(current_downsample * 3 < scan_w &&
-                                               current_downsample * 3 < scan_h)
-                                       {
-                                               scan_w = current_downsample * 3;
-                                               scan_h = current_downsample * 3;
-                                       }
-
-                                       if(angle_step * 1.5 < rotation_range)
-                                       {
-                                               rotation_range = angle_step * 1.5;
-                                       }
-//printf("MotionScan::scan_frame %d %f %f\n", __LINE__, angle_step, rotation_range);
-
-                                       current_downsample /= 2;
-
-// convert back to pixels
+                                       scan_w = (scan_x2 - scan_x1) / 2;
+                                       scan_h = (scan_y2 - scan_y1) / 2;
                                        x_result /= OVERSAMPLE;
                                        y_result /= OVERSAMPLE;
-// debug
-//exit(1);
                                }
-
                        }
                }
 
                dx_result *= -1;
                dy_result *= -1;
-               dr_result *= -1;
        }
-// printf("MotionScan::scan_frame %d dx=%f dy=%f dr=%f\n",
-// __LINE__,
-// (float)dx_result / OVERSAMPLE,
-// (float)dy_result / OVERSAMPLE,
-// dr_result);
+//printf("MotionScan::scan_frame %d\n", __LINE__);
 
 
+       if(vertical_only) dx_result = 0;
+       if(horizontal_only) dy_result = 0;
+
 
 
 // Write results
-       if(!skip && tracking_type == MotionScan::SAVE)
+       if(tracking_type == MotionScan::SAVE)
        {
                char string[BCTEXTLEN];
-
-
-               if(do_motion)
+               sprintf(string, 
+                       "%s%06d", 
+                       MOTION_FILE, 
+                       source_position);
+               FILE *output = fopen(string, "w");
+               if(output)
                {
-                       sprintf(string,
-                               "%s%06d",
-                               MOTION_FILE,
-                               source_position);
-                       FILE *output = fopen(string, "w");
-                       if(output)
-                       {
-                               fprintf(output,
-                                       "%d %d\n",
-                                       dx_result,
-                                       dy_result);
-                               fclose(output);
-                       }
-                       else
-                       {
-                               printf("MotionScan::scan_frame %d: save motion failed\n", __LINE__);
-                       }
+                       fprintf(output, 
+                               "%d %d\n",
+                               dx_result,
+                               dy_result);
+                       fclose(output);
                }
-
-               if(do_rotate)
+               else
                {
-                       sprintf(string,
-                               "%s%06d",
-                               ROTATION_FILE,
-                               source_position);
-                       FILE *output = fopen(string, "w");
-                       if(output)
-                       {
-                               fprintf(output, "%f\n", dr_result);
-                               fclose(output);
-                       }
-                       else
-                       {
-                               printf("MotionScan::scan_frame %d save rotation failed\n", __LINE__);
-                       }
+                       printf("MotionScan::scan_frame %d: save coordinate failed", __LINE__);
                }
        }
 
-
-       if(vertical_only) dx_result = 0;
-       if(horizontal_only) dy_result = 0;
-
-// printf("MotionScan::scan_frame %d dx=%d dy=%d\n",
+// printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n", 
 // __LINE__,
-// this->dx_result,
-// this->dy_result);
+// (float)this->dx_result / OVERSAMPLE,
+// (float)this->dy_result / OVERSAMPLE);
 }
 
 
@@ -1491,6 +768,31 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 
 
 
+int64_t MotionScan::get_cache(int x, int y)
+{
+       int64_t result = -1;
+       cache_lock->lock("MotionScan::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               MotionScanCache *ptr = cache.values[i];
+               if(ptr->x == x && ptr->y == y)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void MotionScan::put_cache(int x, int y, int64_t difference)
+{
+       MotionScanCache *ptr = new MotionScanCache(x, y, difference);
+       cache_lock->lock("MotionScan::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
 
 
 #define ABS_DIFF(type, temp_type, multiplier, components) \
@@ -1506,8 +808,10 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                        { \
                                temp_type difference; \
                                difference = *prev_row++ - *current_row++; \
-                               difference *= difference; \
-                               result_temp += difference; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
                        } \
                        if(components == 4) \
                        { \
@@ -1549,6 +853,12 @@ int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
                case BC_YUVA8888:
                        ABS_DIFF(unsigned char, int64_t, 1, 4)
                        break;
+               case BC_YUV161616:
+                       ABS_DIFF(uint16_t, int64_t, 1, 3)
+                       break;
+               case BC_YUVA16161616:
+                       ABS_DIFF(uint16_t, int64_t, 1, 4)
+                       break;
        }
        return result;
 }
@@ -1583,8 +893,10 @@ int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
                                        0x100 / 0x100; \
                                temp_type current_value = *current_row++; \
                                difference = prev_value - current_value; \
-                               difference *= difference; \
-                               result_temp += difference; \
+                               if(difference < 0) \
+                                       result_temp -= difference; \
+                               else \
+                                       result_temp += difference; \
                        } \
  \
 /* skip alpha */ \
@@ -1639,161 +951,31 @@ int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
                case BC_YUVA8888:
                        ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
                        break;
-       }
-       return result;
-}
-
-
-#if 0
-#define VARIANCE(type, temp_type, multiplier, components) \
-{ \
-       temp_type average[3] = { 0 }; \
-       temp_type variance[3] = { 0 }; \
- \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *row = (type*)current_ptr + i * row_bytes; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               average[k] += row[k]; \
-                       } \
-                       row += components; \
-               } \
-       } \
-       for(int k = 0; k < 3; k++) \
-       { \
-               average[k] /= w * h; \
-       } \
- \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *row = (type*)current_ptr + i * row_bytes; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               variance[k] += SQR(row[k] - average[k]); \
-                       } \
-                       row += components; \
-               } \
-       } \
-       result = (double)multiplier * \
-               sqrt((variance[0] + variance[1] + variance[2]) / w / h / 3); \
-}
-
-double MotionScan::calculate_variance(unsigned char *current_ptr,
-       int row_bytes,
-       int w,
-       int h,
-       int color_model)
-{
-       double result = 0;
-
-       switch(color_model)
-       {
-               case BC_RGB888:
-                       VARIANCE(unsigned char, int, 1, 3)
-                       break;
-               case BC_RGBA8888:
-                       VARIANCE(unsigned char, int, 1, 4)
-                       break;
-               case BC_RGB_FLOAT:
-                       VARIANCE(float, double, 255, 3)
-                       break;
-               case BC_RGBA_FLOAT:
-                       VARIANCE(float, double, 255, 4)
-                       break;
-               case BC_YUV888:
-                       VARIANCE(unsigned char, int, 1, 3)
+               case BC_YUV161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 3)
                        break;
-               case BC_YUVA8888:
-                       VARIANCE(unsigned char, int, 1, 4)
+               case BC_YUVA16161616:
+                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
                        break;
        }
-
-
        return result;
 }
-#endif // 0
 
 
 
 
-#define RANGE(type, temp_type, multiplier, components) \
-{ \
-       temp_type min[3]; \
-       temp_type max[3]; \
-       min[0] = 0x7fff; \
-       min[1] = 0x7fff; \
-       min[2] = 0x7fff; \
-       max[0] = 0; \
-       max[1] = 0; \
-       max[2] = 0; \
- \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *row = (type*)current_ptr + i * row_bytes; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       for(int k = 0; k < 3; k++) \
-                       { \
-                               if(row[k] > max[k]) max[k] = row[k]; \
-                               if(row[k] < min[k]) min[k] = row[k]; \
-                       } \
-                       row += components; \
-               } \
-       } \
- \
-       for(int k = 0; k < 3; k++) \
-       { \
-               /* printf("MotionScan::calculate_range %d k=%d max=%d min=%d\n", __LINE__, k, max[k], min[k]); */ \
-               if(max[k] - min[k] > result) result = max[k] - min[k]; \
-       } \
- \
-}
 
-double MotionScan::calculate_range(unsigned char *current_ptr,
-       int row_bytes,
-       int w,
-       int h,
-       int color_model)
+MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
 {
-       double result = 0;
-
-       switch(color_model)
-       {
-               case BC_RGB888:
-                       RANGE(unsigned char, int, 1, 3)
-                       break;
-               case BC_RGBA8888:
-                       RANGE(unsigned char, int, 1, 4)
-                       break;
-               case BC_RGB_FLOAT:
-                       RANGE(float, float, 255, 3)
-                       break;
-               case BC_RGBA_FLOAT:
-                       RANGE(float, float, 255, 4)
-                       break;
-               case BC_YUV888:
-                       RANGE(unsigned char, int, 1, 3)
-                       break;
-               case BC_YUVA8888:
-                       RANGE(unsigned char, int, 1, 4)
-                       break;
-       }
-
-
-       return result;
+       this->x = x;
+       this->y = y;
+       this->difference = difference;
 }
 
 
-//#define CLAMP_BLOCK
 
-// this truncates the scan area but not the macroblock unless the macro is defined
-void MotionScan::clamp_scan(int w,
-       int h,
+void MotionScan::clamp_scan(int w, 
+       int h, 
        int *block_x1,
        int *block_y1,
        int *block_x2,
@@ -1824,37 +1006,29 @@ void MotionScan::clamp_scan(int w,
 // scan is always out of range before block.
                if(*scan_x1 < 0)
                {
-#ifdef CLAMP_BLOCK
-                       int difference = -*scan_x1;
-                       *block_x1 += difference;
-#endif
+//                     int difference = -*scan_x1;
+//                     *block_x1 += difference;
                        *scan_x1 = 0;
                }
 
                if(*scan_y1 < 0)
                {
-#ifdef CLAMP_BLOCK
-                       int difference = -*scan_y1;
-                       *block_y1 += difference;
-#endif
+//                     int difference = -*scan_y1;
+//                     *block_y1 += difference;
                        *scan_y1 = 0;
                }
 
                if(*scan_x2 > w)
                {
                        int difference = *scan_x2 - w;
-#ifdef CLAMP_BLOCK
-                       *block_x2 -= difference;
-#endif
+//                     *block_x2 -= difference;
                        *scan_x2 -= difference;
                }
 
                if(*scan_y2 > h)
                {
                        int difference = *scan_y2 - h;
-#ifdef CLAMP_BLOCK
-                       *block_y2 -= difference;
-#endif
+//                     *block_y2 -= difference;
                        *scan_y2 -= difference;
                }
 
@@ -1870,9 +1044,7 @@ void MotionScan::clamp_scan(int w,
                if(*scan_x1 < 0)
                {
                        int difference = -*scan_x1;
-#ifdef CLAMP_BLOCK
-                       *block_x1 += difference;
-#endif
+//                     *block_x1 += difference;
                        *scan_x2 += difference;
                        *scan_x1 = 0;
                }
@@ -1880,9 +1052,7 @@ void MotionScan::clamp_scan(int w,
                if(*scan_y1 < 0)
                {
                        int difference = -*scan_y1;
-#ifdef CLAMP_BLOCK
-                       *block_y1 += difference;
-#endif
+//                     *block_y1 += difference;
                        *scan_y2 += difference;
                        *scan_y1 = 0;
                }
@@ -1891,18 +1061,14 @@ void MotionScan::clamp_scan(int w,
                {
                        int difference = *scan_x2 - *block_x1 + *block_x2 - w;
                        *scan_x2 -= difference;
-#ifdef CLAMP_BLOCK
-                       *block_x2 -= difference;
-#endif
+//                     *block_x2 -= difference;
                }
 
                if(*scan_y2 - *block_y1 + *block_y2 > h)
                {
                        int difference = *scan_y2 - *block_y1 + *block_y2 - h;
                        *scan_y2 -= difference;
-#ifdef CLAMP_BLOCK
-                       *block_y2 -= difference;
-#endif
+//                     *block_y2 -= difference;
                }
 
 //             CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
index 72c52980bcb7c6a7eff6e0f5514a9c1736a2d17f..8e756ee38e2297f6839943453651284e4d15afbf 100644 (file)
@@ -1,29 +1,30 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
- *
+ * 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 MOTIONSCAN_H
 #define MOTIONSCAN_H
 
 
-#include "affine.inc"
+#include "arraylist.h"
+//#include "../downsample/downsampleengine.inc"
 #include "loadbalance.h"
 #include "vframe.inc"
 #include <stdint.h>
@@ -32,7 +33,6 @@ class MotionScan;
 
 #define OVERSAMPLE 4
 #define MOTION_FILE "/tmp/m"
-#define ROTATION_FILE "/tmp/r"
 
 class MotionScanPackage : public LoadPackage
 {
@@ -40,11 +40,10 @@ public:
        MotionScanPackage();
 
 // For multiple blocks
-// Position of stationary block after downsampling
+// Position of stationary block
        int block_x1, block_y1, block_x2, block_y2;
-// index of rotated frame
-       int angle_step;
-
+// Range of positions to scan
+       int scan_x1, scan_y1, scan_x2, scan_y2;
        int dx;
        int dy;
        int64_t max_difference;
@@ -52,9 +51,11 @@ public:
        int64_t min_pixel;
        int is_border;
        int valid;
+// For single block
+       int step;
        int64_t difference1;
        int64_t difference2;
-// Search position of current package to nearest pixel with downsampling
+// Search position to nearest pixel
        int search_x;
        int search_y;
 // Subpixel of search position
@@ -62,6 +63,14 @@ public:
        int sub_y;
 };
 
+class MotionScanCache
+{
+public:
+       MotionScanCache(int x, int y, int64_t difference);
+       int x, y;
+       int64_t difference;
+};
+
 class MotionScanUnit : public LoadClient
 {
 public:
@@ -69,16 +78,19 @@ public:
        ~MotionScanUnit();
 
        void process_package(LoadPackage *package);
-       void subpixel(MotionScanPackage *pkg);
-       void single_pixel(MotionScanPackage *pkg);
+       int64_t get_cache(int x, int y);
+       void put_cache(int x, int y, int64_t difference);
 
        MotionScan *server;
+
+       ArrayList<MotionScanCache*> cache;
+       Mutex *cache_lock;
 };
 
 class MotionScan : public LoadServer
 {
 public:
-       MotionScan(int total_clients,
+       MotionScan(int total_clients, 
                int total_packages);
        ~MotionScan();
 
@@ -93,27 +105,27 @@ public:
 // Invoke the motion engine for a search
 // Frame before motion
        void scan_frame(VFrame *previous_frame,
+// Frame after motion
                VFrame *current_frame,
-               int global_range_w, // in pixels
+               int global_range_w,
                int global_range_h,
-               int global_block_w, // in pixels
+               int global_block_w,
                int global_block_h,
-               int block_x, // in pixels
-               int block_y,
+               double block_x,
+               double block_y,
                int frame_type,
                int tracking_type,
                int action_type,
                int horizontal_only,
                int vertical_only,
                int source_position,
-               int total_dx, // in pixels * OVERSAMPLE
+               int total_steps,
+               int total_dx,
                int total_dy,
-               int global_origin_x, // in pixels
-               int global_origin_y,
-               int do_motion,
-               int do_rotate,
-               double rotation_center, // in deg
-               double rotation_range);
+               int global_origin_x,
+               int global_origin_y);
+       int64_t get_cache(int x, int y);
+       void put_cache(int x, int y, int64_t difference);
 
        static int64_t abs_diff(unsigned char *prev_ptr,
                unsigned char *current_ptr,
@@ -131,8 +143,8 @@ public:
                int sub_y);
 
 
-       static void clamp_scan(int w,
-               int h,
+       static void clamp_scan(int w, 
+               int h, 
                int *block_x1,
                int *block_y1,
                int *block_x2,
@@ -143,11 +155,10 @@ public:
                int *scan_y2,
                int use_absolute);
 
-// Change between previous frame and current frame multiplied by
+// Change between previous frame and current frame multiplied by 
 // OVERSAMPLE
        int dx_result;
        int dy_result;
-       float dr_result;
 
        enum
        {
@@ -158,7 +169,7 @@ public:
                STABILIZE_PIXEL,
                NOTHING
        };
-
+       
        enum
        {
 // tracking_type
@@ -167,7 +178,7 @@ public:
                LOAD,
                NO_CALCULATE
        };
-
+       
        enum
        {
 // frame_type
@@ -177,27 +188,6 @@ public:
        };
 
 private:
-       void downsample_frame(VFrame *dst,
-               VFrame *src,
-               int downsample);
-       void pixel_search(int &x_result, int &y_result, double &r_result);
-       void subpixel_search(int &x_result, int &y_result);
-       double step_to_angle(int step, double center);
-
-//     double calculate_variance(unsigned char *current_ptr,
-//             int row_bytes,
-//             int w,
-//             int h,
-//             int color_model);
-       double calculate_range(unsigned char *current_ptr,
-               int row_bytes,
-               int w,
-               int h,
-               int color_model);
-
-
-
-       AffineEngine *rotater;
 // Pointer to downsampled frame before motion
        VFrame *previous_frame;
 // Pointer to downsampled frame after motion
@@ -208,49 +198,33 @@ private:
 // Downsampled frames
        VFrame *downsampled_previous;
        VFrame *downsampled_current;
-// rotated versions of current_frame
-       VFrame **rotated_current;
-// allocation of rotated_current array, a copy of angle_steps
-       int total_rotated;
 // Test for identical frames before processing
 // Faster to skip it if the frames are usually different
        int test_match;
        int skip;
-// macroblocks didn't have enough data
-       int failed;
 // For single block
        int block_x1;
        int block_x2;
        int block_y1;
        int block_y2;
-       int scan_w;
-       int scan_h;
        int scan_x1;
        int scan_y1;
        int scan_x2;
        int scan_y2;
-       double scan_angle1, scan_angle2;
+       int total_pixels;
+       int total_steps;
+       int edge_steps;
        int y_steps;
        int x_steps;
-       int angle_steps;
-// in deg
-       double angle_step;
        int subpixel;
        int horizontal_only;
        int vertical_only;
        int global_origin_x;
        int global_origin_y;
-       int action_type;
-       int current_downsample;
-       int downsampled_w;
-       int downsampled_h;
-       int total_steps;
-       int do_motion;
-       int do_rotate;
-       int rotation_pass;
-// in deg
-       double rotation_center;
-       double rotation_range;
+
+       ArrayList<MotionScanCache*> cache;
+       Mutex *cache_lock;
+//     DownSampleServer *downsample;
 };
 
 
index 4e8229edf2b3788772a82204b79fa0b0fdbeb43a..3c574345a85793601bd075bfee322055f57839ca 100644 (file)
@@ -2,21 +2,21 @@
 /*
  * 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 MOTIONSCAN_INC
index 08c4022c75ea0c2eeb8dc0b7a7dd7d5dfda9cf61..02972d15b1cbef590c20c6cb537b07387d1f1a96 100644 (file)
@@ -53,10 +53,10 @@ void MotionWindow::create_objects()
 
 
 
-//     add_subwindow(global = new MotionGlobal(plugin,
-//             this,
-//             x1,
-//             y));
+       add_subwindow(global = new MotionGlobal(plugin,
+               this,
+               x1,
+               y));
 
        add_subwindow(rotate = new MotionRotate(plugin,
                this,
@@ -108,20 +108,20 @@ void MotionWindow::create_objects()
 //             y,
 //             &plugin->config.rotation_block_h));
 
-//     y += 50;
-//     add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
-//     add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
-//             x1 + title->get_w() + 10,
-//             y,
-//             80));
-//     global_search_positions->create_objects();
-//
-//     add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
-//     add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
-//             x2 + title->get_w() + 10,
-//             y,
-//             80));
-//     rotation_search_positions->create_objects();
+       y += 50;
+       add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
+       add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
+               x1 + title->get_w() + 10,
+               y,
+               80));
+       global_search_positions->create_objects();
+
+       add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
+       add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
+               x2 + title->get_w() + 10,
+               y,
+               80));
+       rotation_search_positions->create_objects();
 
        y += 50;
        add_subwindow(title = new BC_Title(x, y, _("Translation direction:")));
@@ -209,6 +209,11 @@ void MotionWindow::create_objects()
                this,
                x + track_single->get_w() + title->get_w() + 20,
                y));
+       add_subwindow(addtrackedframeoffset = new AddTrackedFrameOffset(plugin,
+               this,
+               x + track_single->get_w() + title->get_w() + 20 + track_frame_number->get_w(),
+               y));
+
 
        y += 20;
        add_subwindow(track_previous = new TrackPreviousFrame(plugin,
@@ -268,8 +273,9 @@ void MotionWindow::update_mode()
                MIN_ROTATION,
                MAX_ROTATION);
        vectors->update(plugin->config.draw_vectors);
-//     global->update(plugin->config.global);
+       global->update(plugin->config.global);
        rotate->update(plugin->config.rotate);
+       addtrackedframeoffset->update(plugin->config.addtrackedframeoffset);
 }
 
 
@@ -391,81 +397,81 @@ int BlockSize::handle_event()
 
 
 
-// GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin,
-//     int x,
-//     int y,
-//     int w)
-//  : BC_PopupMenu(x,
-//     y,
-//     w,
-//     "",
-//     1)
-// {
-//     this->plugin = plugin;
-// }
-// void GlobalSearchPositions::create_objects()
-// {
-//     add_item(new BC_MenuItem("16"));
-//     add_item(new BC_MenuItem("32"));
-//     add_item(new BC_MenuItem("64"));
-//     add_item(new BC_MenuItem("128"));
-//     add_item(new BC_MenuItem("256"));
-//     add_item(new BC_MenuItem("512"));
-//     add_item(new BC_MenuItem("1024"));
-//     add_item(new BC_MenuItem("2048"));
-//     add_item(new BC_MenuItem("4096"));
-//     add_item(new BC_MenuItem("8192"));
-//     add_item(new BC_MenuItem("16384"));
-//     add_item(new BC_MenuItem("32768"));
-//     add_item(new BC_MenuItem("65536"));
-//     add_item(new BC_MenuItem("131072"));
-//     char string[BCTEXTLEN];
-//     sprintf(string, "%d", plugin->config.global_positions);
-//     set_text(string);
-// }
-//
-// int GlobalSearchPositions::handle_event()
-// {
-//     plugin->config.global_positions = atoi(get_text());
-//     plugin->send_configure_change();
-//     return 1;
-// }
-//
-//
-//
-//
-//
-//
-//
-// RotationSearchPositions::RotationSearchPositions(MotionMain *plugin,
-//     int x,
-//     int y,
-//     int w)
-//  : BC_PopupMenu(x,
-//     y,
-//     w,
-//     "",
-//     1)
-// {
-//     this->plugin = plugin;
-// }
-// void RotationSearchPositions::create_objects()
-// {
-//     add_item(new BC_MenuItem("4"));
-//     add_item(new BC_MenuItem("8"));
-//     add_item(new BC_MenuItem("16"));
-//     add_item(new BC_MenuItem("32"));
-//     char string[BCTEXTLEN];
-//     sprintf(string, "%d", plugin->config.rotate_positions);
-//     set_text(string);
-// }
-//
-// int RotationSearchPositions::handle_event()
-// {
-//     plugin->config.rotate_positions = atoi(get_text());
-//     plugin->send_configure_change();
-//     return 1;
-// }
+GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin,
+       int x,
+       int y,
+       int w)
+ : BC_PopupMenu(x,
+       y,
+       w,
+       "",
+       1)
+{
+       this->plugin = plugin;
+}
+void GlobalSearchPositions::create_objects()
+{
+       add_item(new BC_MenuItem("16"));
+       add_item(new BC_MenuItem("32"));
+       add_item(new BC_MenuItem("64"));
+       add_item(new BC_MenuItem("128"));
+       add_item(new BC_MenuItem("256"));
+       add_item(new BC_MenuItem("512"));
+       add_item(new BC_MenuItem("1024"));
+       add_item(new BC_MenuItem("2048"));
+       add_item(new BC_MenuItem("4096"));
+       add_item(new BC_MenuItem("8192"));
+       add_item(new BC_MenuItem("16384"));
+       add_item(new BC_MenuItem("32768"));
+       add_item(new BC_MenuItem("65536"));
+       add_item(new BC_MenuItem("131072"));
+       char string[BCTEXTLEN];
+       sprintf(string, "%d", plugin->config.global_positions);
+       set_text(string);
+}
+
+int GlobalSearchPositions::handle_event()
+{
+       plugin->config.global_positions = atoi(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+RotationSearchPositions::RotationSearchPositions(MotionMain *plugin,
+       int x,
+       int y,
+       int w)
+ : BC_PopupMenu(x,
+       y,
+       w,
+       "",
+       1)
+{
+       this->plugin = plugin;
+}
+void RotationSearchPositions::create_objects()
+{
+       add_item(new BC_MenuItem("4"));
+       add_item(new BC_MenuItem("8"));
+       add_item(new BC_MenuItem("16"));
+       add_item(new BC_MenuItem("32"));
+       char string[BCTEXTLEN];
+       sprintf(string, "%d", plugin->config.rotate_positions);
+       set_text(string);
+}
+
+int RotationSearchPositions::handle_event()
+{
+       plugin->config.rotate_positions = atoi(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
 
 
 
@@ -515,6 +521,27 @@ int MotionReturnSpeed::handle_event()
 
 
 
+AddTrackedFrameOffset::AddTrackedFrameOffset(MotionMain *plugin,
+       MotionWindow *gui,
+       int x,
+       int y)
+ : BC_CheckBox(x,
+       y,
+       plugin->config.addtrackedframeoffset,
+       _("Add (loaded) offset from tracked frame"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int AddTrackedFrameOffset::handle_event()
+{
+       plugin->config.addtrackedframeoffset = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
 MotionRMagnitude::MotionRMagnitude(MotionMain *plugin,
        int x,
        int y)
@@ -559,25 +586,25 @@ int MotionRReturnSpeed::handle_event()
 
 
 
-// MotionGlobal::MotionGlobal(MotionMain *plugin,
-//     MotionWindow *gui,
-//     int x,
-//     int y)
-//  : BC_CheckBox(x,
-//     y,
-//     plugin->config.global,
-//     _("Track translation"))
-// {
-//     this->plugin = plugin;
-//     this->gui = gui;
-// }
-//
-// int MotionGlobal::handle_event()
-// {
-//     plugin->config.global = get_value();
-//     plugin->send_configure_change();
-//     return 1;
-// }
+MotionGlobal::MotionGlobal(MotionMain *plugin,
+       MotionWindow *gui,
+       int x,
+       int y)
+ : BC_CheckBox(x,
+       y,
+       plugin->config.global,
+       _("Track translation"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+
+int MotionGlobal::handle_event()
+{
+       plugin->config.global = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
 
 MotionRotate::MotionRotate(MotionMain *plugin,
        MotionWindow *gui,
index ef977ccb98176bba445c446a1d6cb27cc54efdff..4a66a1a6cbdee42e364f1f0f1a1985070b619bce 100644 (file)
@@ -2,21 +2,21 @@
 /*
  * 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 "guicast.h"
@@ -78,9 +78,9 @@ public:
 class TrackSingleFrame : public BC_Radial
 {
 public:
-       TrackSingleFrame(MotionMain *plugin,
+       TrackSingleFrame(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -90,9 +90,9 @@ public:
 class TrackFrameNumber : public BC_TextBox
 {
 public:
-       TrackFrameNumber(MotionMain *plugin,
+       TrackFrameNumber(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -102,9 +102,9 @@ public:
 class TrackPreviousFrame : public BC_Radial
 {
 public:
-       TrackPreviousFrame(MotionMain *plugin,
+       TrackPreviousFrame(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -114,9 +114,9 @@ public:
 class PreviousFrameSameBlock : public BC_Radial
 {
 public:
-       PreviousFrameSameBlock(MotionMain *plugin,
+       PreviousFrameSameBlock(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -126,8 +126,8 @@ public:
 class GlobalRange : public BC_IPot
 {
 public:
-       GlobalRange(MotionMain *plugin,
-               int x,
+       GlobalRange(MotionMain *plugin, 
+               int x, 
                int y,
                int *value);
        int handle_event();
@@ -138,8 +138,8 @@ public:
 class RotationRange : public BC_IPot
 {
 public:
-       RotationRange(MotionMain *plugin,
-               int x,
+       RotationRange(MotionMain *plugin, 
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -148,8 +148,8 @@ public:
 class RotationCenter : public BC_IPot
 {
 public:
-       RotationCenter(MotionMain *plugin,
-               int x,
+       RotationCenter(MotionMain *plugin, 
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -158,8 +158,8 @@ public:
 class BlockSize : public BC_IPot
 {
 public:
-       BlockSize(MotionMain *plugin,
-               int x,
+       BlockSize(MotionMain *plugin, 
+               int x, 
                int y,
                int *value);
        int handle_event();
@@ -170,9 +170,9 @@ public:
 class MotionBlockX : public BC_FPot
 {
 public:
-       MotionBlockX(MotionMain *plugin,
+       MotionBlockX(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionWindow *gui;
@@ -182,9 +182,9 @@ public:
 class MotionBlockY : public BC_FPot
 {
 public:
-       MotionBlockY(MotionMain *plugin,
+       MotionBlockY(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionWindow *gui;
@@ -194,9 +194,9 @@ public:
 class MotionBlockXText : public BC_TextBox
 {
 public:
-       MotionBlockXText(MotionMain *plugin,
+       MotionBlockXText(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionWindow *gui;
@@ -206,44 +206,44 @@ public:
 class MotionBlockYText : public BC_TextBox
 {
 public:
-       MotionBlockYText(MotionMain *plugin,
+       MotionBlockYText(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionWindow *gui;
        MotionMain *plugin;
 };
 
-// class GlobalSearchPositions : public BC_PopupMenu
-// {
-// public:
-//     GlobalSearchPositions(MotionMain *plugin,
-//             int x,
-//             int y,
-//             int w);
-//     void create_objects();
-//     int handle_event();
-//     MotionMain *plugin;
-// };
-//
-// class RotationSearchPositions : public BC_PopupMenu
-// {
-// public:
-//     RotationSearchPositions(MotionMain *plugin,
-//             int x,
-//             int y,
-//             int w);
-//     void create_objects();
-//     int handle_event();
-//     MotionMain *plugin;
-// };
+class GlobalSearchPositions : public BC_PopupMenu
+{
+public:
+       GlobalSearchPositions(MotionMain *plugin, 
+               int x, 
+               int y,
+               int w);
+       void create_objects();
+       int handle_event();
+       MotionMain *plugin;
+};
+
+class RotationSearchPositions : public BC_PopupMenu
+{
+public:
+       RotationSearchPositions(MotionMain *plugin, 
+               int x, 
+               int y,
+               int w);
+       void create_objects();
+       int handle_event();
+       MotionMain *plugin;
+};
 
 class MotionMagnitude : public BC_IPot
 {
 public:
-       MotionMagnitude(MotionMain *plugin,
-               int x,
+       MotionMagnitude(MotionMain *plugin, 
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -252,8 +252,8 @@ public:
 class MotionRMagnitude : public BC_IPot
 {
 public:
-       MotionRMagnitude(MotionMain *plugin,
-               int x,
+       MotionRMagnitude(MotionMain *plugin, 
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -262,8 +262,8 @@ public:
 class MotionReturnSpeed : public BC_IPot
 {
 public:
-       MotionReturnSpeed(MotionMain *plugin,
-               int x,
+       MotionReturnSpeed(MotionMain *plugin, 
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -273,8 +273,8 @@ public:
 class MotionRReturnSpeed : public BC_IPot
 {
 public:
-       MotionRReturnSpeed(MotionMain *plugin,
-               int x,
+       MotionRReturnSpeed(MotionMain *plugin, 
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -284,9 +284,9 @@ public:
 class MotionDrawVectors : public BC_CheckBox
 {
 public:
-       MotionDrawVectors(MotionMain *plugin,
+       MotionDrawVectors(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionMain *plugin;
@@ -296,33 +296,33 @@ public:
 class AddTrackedFrameOffset : public BC_CheckBox
 {
 public:
-       AddTrackedFrameOffset(MotionMain *plugin,
+       AddTrackedFrameOffset(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionWindow *gui;
        MotionMain *plugin;
 };
 
-// class MotionGlobal : public BC_CheckBox
-// {
-// public:
-//     MotionGlobal(MotionMain *plugin,
-//             MotionWindow *gui,
-//             int x,
-//             int y);
-//     int handle_event();
-//     MotionWindow *gui;
-//     MotionMain *plugin;
-// };
+class MotionGlobal : public BC_CheckBox
+{
+public:
+       MotionGlobal(MotionMain *plugin, 
+               MotionWindow *gui,
+               int x, 
+               int y);
+       int handle_event();
+       MotionWindow *gui;
+       MotionMain *plugin;
+};
 
 class MotionRotate : public BC_CheckBox
 {
 public:
-       MotionRotate(MotionMain *plugin,
+       MotionRotate(MotionMain *plugin, 
                MotionWindow *gui,
-               int x,
+               int x, 
                int y);
        int handle_event();
        MotionWindow *gui;
@@ -353,15 +353,15 @@ public:
        MotionBlockY *block_y;
        MotionBlockXText *block_x_text;
        MotionBlockYText *block_y_text;
-//     GlobalSearchPositions *global_search_positions;
-//     RotationSearchPositions *rotation_search_positions;
+       GlobalSearchPositions *global_search_positions;
+       RotationSearchPositions *rotation_search_positions;
        MotionMagnitude *magnitude;
        MotionRMagnitude *rotate_magnitude;
        MotionReturnSpeed *return_speed;
        MotionRReturnSpeed *rotate_return_speed;
        ActionType *action_type;
        MotionDrawVectors *vectors;
-//     MotionGlobal *global;
+       MotionGlobal *global;
        MotionRotate *rotate;
        AddTrackedFrameOffset *addtrackedframeoffset;
        TrackSingleFrame *track_single;
index 8fbef4672d9b8bf70bfc82ff079451253a0643b3..50404d715a5af075e55a3c087ca11a256d5887c5 100644 (file)
@@ -2,21 +2,21 @@
 /*
  * 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 MOTIONWINDOW_INC
index 3fadcf0d7bc0c09f1f2d6e3e72b098eb0d4619c6..7c19be6821ac6884d28dedeb7fee7a2b8a7ae956 100644 (file)
@@ -1,21 +1,21 @@
 /*
  * 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
- *
+ * 
  */
 
 
@@ -128,10 +128,10 @@ findPairs( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors,
 
 
 void
-flannFindPairs( const CvSeq*,
+flannFindPairs( const CvSeq*, 
        const CvSeq* objectDescriptors,
-    const CvSeq*,
-       const CvSeq* imageDescriptors,
+    const CvSeq*, 
+       const CvSeq* imageDescriptors, 
        vector<int>& ptpairs )
 {
        int length = (int)(objectDescriptors->elem_size/sizeof(float));
@@ -171,10 +171,10 @@ flannFindPairs( const CvSeq*,
     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)
+    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])
+       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);
@@ -185,11 +185,11 @@ flannFindPairs( const CvSeq*,
 
 
 /* a rough implementation for object location */
-int OpenCVWrapper::locatePlanarObject(const CvSeq* objectKeypoints,
+int OpenCVWrapper::locatePlanarObject(const CvSeq* objectKeypoints, 
        const CvSeq* objectDescriptors,
-    const CvSeq* imageKeypoints,
+    const CvSeq* imageKeypoints, 
        const CvSeq* imageDescriptors,
-    const CvPoint src_corners[4],
+    const CvPoint src_corners[4], 
        int *(*point_pairs),
        int (*total_pairs))
 {
@@ -199,7 +199,7 @@ int OpenCVWrapper::locatePlanarObject(const CvSeq* objectKeypoints,
     vector<CvPoint2D32f> pt1, pt2;
     CvMat _pt1, _pt2;
     int i, n;
-
+       
        (*point_pairs) = 0;
        (*total_pairs) = 0;
 
@@ -213,8 +213,8 @@ int OpenCVWrapper::locatePlanarObject(const CvSeq* objectKeypoints,
 // 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];
@@ -292,7 +292,7 @@ OpenCVWrapper::~OpenCVWrapper()
 
 int OpenCVWrapper::scan(VFrame *object_frame,
        VFrame *scene_frame,
-       int object_x1,
+       int object_x1, 
        int object_y1,
        int object_x2,
        int object_y2,
@@ -321,7 +321,7 @@ int OpenCVWrapper::scan(VFrame *object_frame,
        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 &&
+       if(object_image && 
                (object_image_w != this->object_image_w ||
                object_image_h != this->object_image_h))
        {
@@ -331,7 +331,7 @@ int OpenCVWrapper::scan(VFrame *object_frame,
        this->object_image_w = object_image_w;
        this->object_image_h = object_image_h;
 
-       if(scene_image &&
+       if(scene_image && 
                (scene_image_w != this->scene_image_w ||
                scene_image_h != this->scene_image_h))
        {
@@ -345,18 +345,18 @@ int OpenCVWrapper::scan(VFrame *object_frame,
        if(!object_image)
        {
 // Only does greyscale
-               object_image = cvCreateImage(
-                       cvSize(object_image_w, object_image_h),
-                       8,
+               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,
+               scene_image = cvCreateImage( 
+                       cvSize(scene_image_w, scene_image_h), 
+                       8, 
                        1);
        }
 
@@ -365,19 +365,19 @@ int OpenCVWrapper::scan(VFrame *object_frame,
        cvSetImageROI( object_image, cvRect( 0, 0, object_w, object_h ) );
        cvSetImageROI( scene_image, cvRect( 0, 0, scene_w, scene_h ) );
 
-       grey_crop((unsigned char*)scene_image->imageData,
-               scene_frame,
-               scene_x1,
-               scene_y1,
-               scene_x2,
+       grey_crop((unsigned char*)scene_image->imageData, 
+               scene_frame, 
+               scene_x1, 
+               scene_y1, 
+               scene_x2, 
                scene_y2,
                scene_image_w,
                scene_image_h);
-       grey_crop((unsigned char*)object_image->imageData,
-               object_frame,
-               object_x1,
-               object_y1,
-               object_x2,
+       grey_crop((unsigned char*)object_image->imageData, 
+               object_frame, 
+               object_x1, 
+               object_y1, 
+               object_x2, 
                object_y2,
                object_image_w,
                object_image_h);
@@ -404,11 +404,11 @@ int OpenCVWrapper::scan(VFrame *object_frame,
        point_pairs = 0;
 
 
-       cvExtractSURF(object_image,
-               0,
-               &object_keypoints,
-               &object_descriptors,
-               storage,
+       cvExtractSURF(object_image, 
+               0, 
+               &object_keypoints, 
+               &object_descriptors, 
+               storage, 
                params,
                0);
 
@@ -418,21 +418,21 @@ int OpenCVWrapper::scan(VFrame *object_frame,
 //             {
 //             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,
+//                     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("OpenCVWrapper::process_buffer %d\n", __LINE__);
 
-       cvExtractSURF(scene_image,
-               0,
-               &scene_keypoints,
-               &scene_descriptors,
-               storage,
+       cvExtractSURF(scene_image, 
+               0, 
+               &scene_keypoints, 
+               &scene_descriptors, 
+               storage, 
                params,
                0);
 
@@ -441,24 +441,24 @@ int OpenCVWrapper::scan(VFrame *object_frame,
 //             {
 //             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,
+//                     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("OpenCVWrapper::scan %d %d %d scene keypoints=%d\n",
-// __LINE__,
+// printf("OpenCVWrapper::scan %d %d %d scene keypoints=%d\n", 
+// __LINE__, 
 // scene_w,
 // scene_h,
 // scene_keypoints->total);
 
-       CvPoint src_corners[4] =
+       CvPoint src_corners[4] = 
        {
-               { 0, 0 },
-               { object_w, 0 },
-               { object_w, object_h },
+               { 0, 0 }, 
+               { object_w, 0 }, 
+               { object_w, object_h }, 
                { 0, object_h }
        };
 
@@ -472,11 +472,11 @@ int OpenCVWrapper::scan(VFrame *object_frame,
 //printf("OpenCVWrapper::process_buffer %d\n", __LINE__);
        if(scene_keypoints->total &&
                object_keypoints->total &&
-               locatePlanarObject(object_keypoints,
-                       object_descriptors,
-                       scene_keypoints,
-                       scene_descriptors,
-                       src_corners,
+               locatePlanarObject(object_keypoints, 
+                       object_descriptors, 
+                       scene_keypoints, 
+                       scene_descriptors, 
+                       src_corners, 
                        &point_pairs,
                        &total_pairs))
        {
@@ -493,9 +493,9 @@ int OpenCVWrapper::scan(VFrame *object_frame,
 
 
 // Convert to greyscale & crop
-void OpenCVWrapper::grey_crop(unsigned char *dst,
-       VFrame *src,
-       int x1,
+void OpenCVWrapper::grey_crop(unsigned char *dst, 
+       VFrame *src, 
+       int x1, 
        int y1,
        int x2,
        int y2,
index 53e0c46b17830609e8ae71b036186f0b59055d1b..a33bec7f70d01e297710671acba44b5388eccb94 100644 (file)
@@ -1,21 +1,21 @@
 /*
  * 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
- *
+ * 
  */
 
 
@@ -37,9 +37,9 @@ public:
        float get_dst_x(int number);
        float get_dst_y(int number);
 
-       void grey_crop(unsigned char *dst,
-               VFrame *src,
-               int x1,
+       void grey_crop(unsigned char *dst, 
+               VFrame *src, 
+               int x1, 
                int y1,
                int x2,
                int y2,
@@ -49,7 +49,7 @@ public:
 // Returns 1 when it got something
        int scan(VFrame *object_frame,
                VFrame *scene_frame,
-               int object_x1,
+               int object_x1, 
                int object_y1,
                int object_x2,
                int object_y2,
@@ -59,11 +59,11 @@ public:
                int scene_y2);
 
 private:
-       int locatePlanarObject(const CvSeq* objectKeypoints,
+       int locatePlanarObject(const CvSeq* objectKeypoints, 
                const CvSeq* objectDescriptors,
-       const CvSeq* imageKeypoints,
+       const CvSeq* imageKeypoints, 
                const CvSeq* imageDescriptors,
-       const CvPoint src_corners[4],
+       const CvPoint src_corners[4], 
                int *(*point_pairs),
                int (*total_pairs));
 
diff --git a/cinelerra-5.1/plugins/motion/rotatescan.C b/cinelerra-5.1/plugins/motion/rotatescan.C
deleted file mode 100644 (file)
index e7b346e..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-
-/*
- * CINELERRA
- * Copyright (C) 2016 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 "affine.h"
-#include "bcsignals.h"
-#include "clip.h"
-#include "motionscan.h"
-#include "rotatescan.h"
-#include "motion.h"
-#include "mutex.h"
-#include "vframe.h"
-
-
-
-
-
-
-
-
-
-RotateScanPackage::RotateScanPackage()
-{
-}
-
-
-RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
- : LoadClient(server)
-{
-       this->server = server;
-       this->plugin = plugin;
-       rotater = 0;
-       temp = 0;
-}
-
-RotateScanUnit::~RotateScanUnit()
-{
-       delete rotater;
-       delete temp;
-}
-
-void RotateScanUnit::process_package(LoadPackage *package)
-{
-       if(server->skip) return;
-       RotateScanPackage *pkg = (RotateScanPackage*)package;
-
-       if((pkg->difference = server->get_cache(pkg->angle)) < 0)
-       {
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-               int color_model = server->previous_frame->get_color_model();
-               int pixel_size = BC_CModels::calculate_pixelsize(color_model);
-               int row_bytes = server->previous_frame->get_bytes_per_line();
-
-               if(!rotater)
-                       rotater = new AffineEngine(1, 1);
-               if(!temp) temp = new VFrame(0,
-                       -1,
-                       server->previous_frame->get_w(),
-                       server->previous_frame->get_h(),
-                       color_model,
-                       -1);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-
-
-// Rotate original block size
-//             rotater->set_viewport(server->block_x1,
-//                     server->block_y1,
-//                     server->block_x2 - server->block_x1,
-//                     server->block_y2 - server->block_y1);
-               rotater->set_in_viewport(server->block_x1,
-                       server->block_y1,
-                       server->block_x2 - server->block_x1,
-                       server->block_y2 - server->block_y1);
-               rotater->set_out_viewport(server->block_x1,
-                       server->block_y1,
-                       server->block_x2 - server->block_x1,
-                       server->block_y2 - server->block_y1);
-//             rotater->set_pivot(server->block_x, server->block_y);
-               rotater->set_in_pivot(server->block_x, server->block_y);
-               rotater->set_out_pivot(server->block_x, server->block_y);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-               rotater->rotate(temp,
-                       server->previous_frame,
-                       pkg->angle);
-
-// Scan reduced block size
-//plugin->output_frame->copy_from(server->current_frame);
-//plugin->output_frame->copy_from(temp);
-// printf("RotateScanUnit::process_package %d %d %d %d %d\n",
-// __LINE__,
-// server->scan_x,
-// server->scan_y,
-// server->scan_w,
-// server->scan_h);
-// Clamp coordinates
-               int x1 = server->scan_x;
-               int y1 = server->scan_y;
-               int x2 = x1 + server->scan_w;
-               int y2 = y1 + server->scan_h;
-               x2 = MIN(temp->get_w(), x2);
-               y2 = MIN(temp->get_h(), y2);
-               x2 = MIN(server->current_frame->get_w(), x2);
-               y2 = MIN(server->current_frame->get_h(), y2);
-               x1 = MAX(0, x1);
-               y1 = MAX(0, y1);
-
-               if(x2 > x1 && y2 > y1)
-               {
-                       pkg->difference = MotionScan::abs_diff(
-                               temp->get_rows()[y1] + x1 * pixel_size,
-                               server->current_frame->get_rows()[y1] + x1 * pixel_size,
-                               row_bytes,
-                               x2 - x1,
-                               y2 - y1,
-                               color_model);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-                       server->put_cache(pkg->angle, pkg->difference);
-               }
-
-// printf("RotateScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%lld\n",
-// server->block_x1,
-// server->block_y1,
-// server->block_x2 - server->block_x1,
-// server->block_y2 - server->block_y1,
-// server->block_x,
-// server->block_y,
-// pkg->angle,
-// server->scan_w,
-// server->scan_h,
-// pkg->difference);
-       }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-RotateScan::RotateScan(MotionMain *plugin,
-       int total_clients,
-       int total_packages)
- : LoadServer(
-//1, 1
-total_clients, total_packages
-)
-{
-       this->plugin = plugin;
-       cache_lock = new Mutex("RotateScan::cache_lock");
-}
-
-
-RotateScan::~RotateScan()
-{
-       delete cache_lock;
-}
-
-void RotateScan::init_packages()
-{
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
-               pkg->angle = i *
-                       (scan_angle2 - scan_angle1) /
-                       (total_steps - 1) +
-                       scan_angle1;
-       }
-}
-
-LoadClient* RotateScan::new_client()
-{
-       return new RotateScanUnit(this, plugin);
-}
-
-LoadPackage* RotateScan::new_package()
-{
-       return new RotateScanPackage;
-}
-
-
-float RotateScan::scan_frame(VFrame *previous_frame,
-       VFrame *current_frame,
-       int block_x,
-       int block_y)
-{
-       skip = 0;
-       this->block_x = block_x;
-       this->block_y = block_y;
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
-       switch(plugin->config.tracking_type)
-       {
-               case MotionScan::NO_CALCULATE:
-                       result = plugin->config.rotation_center;
-                       skip = 1;
-                       break;
-
-               case MotionScan::LOAD:
-               {
-                       char string[BCTEXTLEN];
-                       sprintf(string,
-                               "%s%06ld",
-                               ROTATION_FILE,
-                               plugin->get_source_position());
-                       FILE *input = fopen(string, "r");
-                       if(input)
-                       {
-                               int temp = fscanf(input, "%f", &result);
-                               fclose(input);
-                               skip = 1;
-                       }
-                       else
-                       {
-                               perror("RotateScan::scan_frame LOAD");
-                       }
-                       break;
-               }
-       }
-
-
-
-
-
-
-
-
-       this->previous_frame = previous_frame;
-       this->current_frame = current_frame;
-       int w = current_frame->get_w();
-       int h = current_frame->get_h();
-       int block_w = w * plugin->config.global_block_w / 100;
-       int block_h = h * plugin->config.global_block_h / 100;
-
-       if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
-       if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
-       if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
-       if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
-
-       block_x1 = this->block_x - block_w / 2;
-       block_x2 = this->block_x + block_w / 2;
-       block_y1 = this->block_y - block_h / 2;
-       block_y2 = this->block_y + block_h / 2;
-
-
-// Calculate the maximum area available to scan after rotation.
-// Must be calculated from the starting range because of cache.
-// Get coords of rectangle after rotation.
-       double center_x = this->block_x;
-       double center_y = this->block_y;
-       double max_angle = plugin->config.rotation_range;
-       double base_angle1 = atan((float)block_h / block_w);
-       double base_angle2 = atan((float)block_w / block_h);
-       double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
-       double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
-       double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
-       double x1 = center_x - cos(target_angle1) * radius;
-       double y1 = center_y - sin(target_angle1) * radius;
-       double x2 = center_x + sin(target_angle2) * radius;
-       double y2 = center_y - cos(target_angle2) * radius;
-       double x3 = center_x - sin(target_angle2) * radius;
-       double y3 = center_y + cos(target_angle2) * radius;
-
-// Track top edge to find greatest area.
-       double max_area1 = 0;
-       double max_x1 = 0;
-       double max_y1 = 0;
-       for(double x = x1; x < x2; x++)
-       {
-               double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
-               if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
-               {
-                       double area = fabs(x - center_x) * fabs(y - center_y);
-                       if(area > max_area1)
-                       {
-                               max_area1 = area;
-                               max_x1 = x;
-                               max_y1 = y;
-                       }
-               }
-       }
-
-// Track left edge to find greatest area.
-       double max_area2 = 0;
-       double max_x2 = 0;
-       double max_y2 = 0;
-       for(double y = y1; y < y3; y++)
-       {
-               double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
-               if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
-               {
-                       double area = fabs(x - center_x) * fabs(y - center_y);
-                       if(area > max_area2)
-                       {
-                               max_area2 = area;
-                               max_x2 = x;
-                               max_y2 = y;
-                       }
-               }
-       }
-
-       double max_x, max_y;
-       max_x = max_x2;
-       max_y = max_y1;
-
-// Get reduced scan coords
-       scan_w = (int)(fabs(max_x - center_x) * 2);
-       scan_h = (int)(fabs(max_y - center_y) * 2);
-       scan_x = (int)(center_x - scan_w / 2);
-       scan_y = (int)(center_y - scan_h / 2);
-// printf("RotateScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n",
-// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
-// printf("    angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
-
-// Determine min angle from size of block
-       double angle1 = atan((double)block_h / block_w);
-       double angle2 = atan((double)(block_h - 1) / (block_w + 1));
-       double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
-       min_angle = MAX(min_angle, MIN_ANGLE);
-
-//printf("RotateScan::scan_frame %d min_angle=%f\n", __LINE__, min_angle * 360 / 2 / M_PI);
-
-       cache.remove_all_objects();
-
-
-       if(!skip)
-       {
-               if(previous_frame->data_matches(current_frame))
-               {
-//printf("RotateScan::scan_frame: frames match.  Skipping.\n");
-                       result = plugin->config.rotation_center;
-                       skip = 1;
-               }
-       }
-
-       if(!skip)
-       {
-// Initial search range
-               float angle_range = max_angle;
-               result = plugin->config.rotation_center;
-               total_steps = plugin->config.rotate_positions;
-
-
-               while(angle_range >= min_angle * total_steps)
-               {
-                       scan_angle1 = result - angle_range;
-                       scan_angle2 = result + angle_range;
-
-
-                       set_package_count(total_steps);
-//set_package_count(1);
-                       process_packages();
-
-                       int64_t min_difference = -1;
-                       for(int i = 0; i < get_total_packages(); i++)
-                       {
-                               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
-                               if(pkg->difference < min_difference || min_difference == -1)
-                               {
-                                       min_difference = pkg->difference;
-                                       result = pkg->angle;
-                               }
-//break;
-                       }
-
-                       angle_range /= 2;
-
-//break;
-               }
-       }
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
-
-       if(!skip && plugin->config.tracking_type == MotionScan::SAVE)
-       {
-               char string[BCTEXTLEN];
-               sprintf(string,
-                       "%s%06ld",
-                       ROTATION_FILE,
-                       plugin->get_source_position());
-               FILE *output = fopen(string, "w");
-               if(output)
-               {
-                       fprintf(output, "%f\n", result);
-                       fclose(output);
-               }
-               else
-               {
-                       perror("RotateScan::scan_frame SAVE");
-               }
-       }
-
-//printf("RotateScan::scan_frame %d angle=%f\n", __LINE__, result);
-
-
-
-       return result;
-}
-
-int64_t RotateScan::get_cache(float angle)
-{
-       int64_t result = -1;
-       cache_lock->lock("RotateScan::get_cache");
-       for(int i = 0; i < cache.total; i++)
-       {
-               RotateScanCache *ptr = cache.values[i];
-               if(fabs(ptr->angle - angle) <= MIN_ANGLE)
-               {
-                       result = ptr->difference;
-                       break;
-               }
-       }
-       cache_lock->unlock();
-       return result;
-}
-
-void RotateScan::put_cache(float angle, int64_t difference)
-{
-       RotateScanCache *ptr = new RotateScanCache(angle, difference);
-       cache_lock->lock("RotateScan::put_cache");
-       cache.append(ptr);
-       cache_lock->unlock();
-}
-
-
-
-
-
-
-
-
-
-RotateScanCache::RotateScanCache(float angle, int64_t difference)
-{
-       this->angle = angle;
-       this->difference = difference;
-}
-
-
-
diff --git a/cinelerra-5.1/plugins/motion/rotatescan.h b/cinelerra-5.1/plugins/motion/rotatescan.h
deleted file mode 100644 (file)
index 27001e3..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-
-/*
- * CINELERRA
- * Copyright (C) 2016 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 ROTATESCAN_H
-#define ROTATESCAN_H
-
-
-
-#include "affine.inc"
-#include "loadbalance.h"
-#include "motion.inc"
-#include "vframe.inc"
-#include <stdint.h>
-
-class RotateScan;
-
-
-class RotateScanPackage : public LoadPackage
-{
-public:
-       RotateScanPackage();
-       float angle;
-       int64_t difference;
-};
-
-class RotateScanCache
-{
-public:
-       RotateScanCache(float angle, int64_t difference);
-       float angle;
-       int64_t difference;
-};
-
-class RotateScanUnit : public LoadClient
-{
-public:
-       RotateScanUnit(RotateScan *server, MotionMain *plugin);
-       ~RotateScanUnit();
-
-       void process_package(LoadPackage *package);
-
-       RotateScan *server;
-       MotionMain *plugin;
-       AffineEngine *rotater;
-       VFrame *temp;
-};
-
-class RotateScan : public LoadServer
-{
-public:
-       RotateScan(MotionMain *plugin,
-               int total_clients,
-               int total_packages);
-       ~RotateScan();
-
-       friend class RotateScanUnit;
-
-       void init_packages();
-       LoadClient* new_client();
-       LoadPackage* new_package();
-
-// Invoke the motion engine for a search
-// Frame before rotation
-       float scan_frame(VFrame *previous_frame,
-// Frame after rotation
-               VFrame *current_frame,
-// Pivot
-               int block_x,
-               int block_y);
-       int64_t get_cache(float angle);
-       void put_cache(float angle, int64_t difference);
-
-
-// Angle result
-       float result;
-
-private:
-       VFrame *previous_frame;
-// Frame after motion
-       VFrame *current_frame;
-
-       MotionMain *plugin;
-       int skip;
-
-// Pivot
-       int block_x;
-       int block_y;
-// Block to rotate
-       int block_x1;
-       int block_x2;
-       int block_y1;
-       int block_y2;
-// Area to compare
-       int scan_x;
-       int scan_y;
-       int scan_w;
-       int scan_h;
-// Range of angles to compare
-       float scan_angle1, scan_angle2;
-       int total_steps;
-
-       ArrayList<RotateScanCache*> cache;
-       Mutex *cache_lock;
-};
-
-
-
-
-
-#endif
-
-
-
-
-
diff --git a/cinelerra-5.1/plugins/motion/rotatescan.inc b/cinelerra-5.1/plugins/motion/rotatescan.inc
deleted file mode 100644 (file)
index d3dfd97..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef ROTATESCAN_INC
-#define ROTATESCAN_INC
-
-
-class RotateScan;
-
-
-#endif
-
-
-
-
index 914cf00dc277ebb4a2256ef6a4c6a049d111af2f..5a00398c627d9584cf251c8c78cec20baa0d3778 100644 (file)
@@ -2,15 +2,17 @@ include ../../plugin_defs
 
 OBJS := \
        $(OBJDIR)/downsampleengine.o \
-       $(OBJDIR)/motionscan.o \
+       $(OBJDIR)/motionscan-hv.o \
        $(OBJDIR)/motion.o \
        $(OBJDIR)/motionwindow.o
 
+CFLAGS += -DMotionScan=MotionHVScan
+
 PLUGIN = motion2
 
 include ../../plugin_config
 
 $(OBJDIR)/downsampleengine.o: downsampleengine.C
 $(OBJDIR)/motion.o: motion.C
-$(OBJDIR)/motionscan.o: motionscan.C
+$(OBJDIR)/motionscan-hv.o: motionscan-hv.C
 $(OBJDIR)/motionwindow.o: motionwindow.C
index 28c09378f67b7f7fa2606a31cf1f9e5140eece77..ad745c4f2b0fbb009bf80baa2fd698e513b9b497 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #include "affine.h"
-#include "../motion/motionscan.h"
+#include "../motion-hv/motionscan-hv.h"
 #include "bcdisplayinfo.h"
 #include "bcsignals.h"
 #include "clip.h"
index 0fd65948504ab6ca944a4a0bc795930abb427790..19d1fa658e9202b41937d4888379e80d1c1e0616 100644 (file)
@@ -27,7 +27,7 @@
 #include <string.h>
 
 #include "affine.inc"
-#include "motionscan.inc"
+#include "motionscan-hv.inc"
 #include "bchash.inc"
 #include "filexml.inc"
 #include "keyframe.inc"
diff --git a/cinelerra-5.1/plugins/motion2point/motionscan-hv.C b/cinelerra-5.1/plugins/motion2point/motionscan-hv.C
new file mode 120000 (symlink)
index 0000000..898c188
--- /dev/null
@@ -0,0 +1 @@
+../motion-hv/motionscan-hv.C
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/motion2point/motionscan-hv.h b/cinelerra-5.1/plugins/motion2point/motionscan-hv.h
new file mode 120000 (symlink)
index 0000000..d5eb987
--- /dev/null
@@ -0,0 +1 @@
+../motion-hv/motionscan-hv.h
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/motion2point/motionscan-hv.inc b/cinelerra-5.1/plugins/motion2point/motionscan-hv.inc
new file mode 120000 (symlink)
index 0000000..4c59354
--- /dev/null
@@ -0,0 +1 @@
+../motion-hv/motionscan-hv.inc
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/motion2point/motionscan.C b/cinelerra-5.1/plugins/motion2point/motionscan.C
deleted file mode 120000 (symlink)
index 4ac1472..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../motion/motionscan.C
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/motion2point/motionscan.h b/cinelerra-5.1/plugins/motion2point/motionscan.h
deleted file mode 120000 (symlink)
index 9461913..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../motion/motionscan.h
\ No newline at end of file
diff --git a/cinelerra-5.1/plugins/motion2point/motionscan.inc b/cinelerra-5.1/plugins/motion2point/motionscan.inc
deleted file mode 120000 (symlink)
index e4b8d55..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../motion/motionscan.inc
\ No newline at end of file
index ad959d8cc2fcb5dc2411f3e4b5fbdeffc1ed5f36..ccfbe5046040bdde5d4f572008e8e3b25b4e2209 100644 (file)
@@ -24,7 +24,7 @@
 #include "clip.h"
 #include "language.h"
 #include "motion.h"
-#include "motionscan.h"
+#include "motionscan-hv.h"
 #include "motionwindow.h"
 
 
index a7e7cd632c47f46c67f89830d017c3cfcb5fa63a..c7cc7f3ca1aa0a45c8d9184217cbabcd131cfd66 100644 (file)
@@ -160,7 +160,7 @@ a52dec.mak_params?= ; cd $(call bld_path,a52dec,include); ln -sf . a52dec
 a52dec.cfg_vars?= CFLAGS+=" -U__FreeBSD__ $(call inc_path,djbfft)" LIBS+=" $(call ld_path,djbfft)"
 a52dec.cfg_params?=--enable-djbfft
 djbfft.cfg_vars?=echo "$(call bld_path,djbfft)" > conf-home; \
- (CFLAGS="$(CFLAGS)"; $(CFG_VARS)echo "$(CC) $$$$CFLAGS") > conf-cc; \
+ (CFLAGS="$(CFLAGS)"; $(CFG_VARS)$(if $(CFG_VARS),; )echo "$(CC) $$$$CFLAGS") > conf-cc; \
  echo > ./configure; chmod +x ./configure;
 djbfft.mak_params?=; cd $(call bld_path,djbfft); ln -sf djbfft.a libdjbfft.a
 audiofile.cfg_params?=--enable-shared=no