(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;
if( ret < 0 ) {
ff_err(ret, "FFMPEG::encode_activate: write header failed %s\n",
fmt_ctx->filename);
- return 1;
+ return -1;
}
encoding = 1;
}
--- /dev/null
+f4v libmp3lame
--- /dev/null
+flv libmp3lame
+# sample rate must be: 44100 or 22050 or 11025
# apply at init encode
+loglevel=error
threads=auto
side_data_only_packets=1
--- /dev/null
+avi mpeg4
+vtag xvid
--- /dev/null
+f4v libx264
+profile=baseline
+level=3.0
+preset=medium
+x264opts keyint=25:min-keyint=4:qpmin=3:qpmax=33:qp_step=4:merange=8
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
loopaudio \
loopvideo \
motion \
+ motion-cv \
+ motion-hv \
motion2point \
motionblur \
normalize \
OBJS = $(OBJDIR)/interpolatevideo.o \
$(OBJDIR)/interpolatewindow.o \
$(OBJDIR)/opticflow.o \
- $(OBJDIR)/motionscan.o
+ $(OBJDIR)/motionscan-hv.o
+
+CFLAGS += -DMotionScan=MotionHVScan
PLUGIN = interpolatevideo
$(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
#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>
--- /dev/null
+../motion-hv/motionscan-hv.C
\ No newline at end of file
--- /dev/null
+../motion-hv/motionscan-hv.h
\ No newline at end of file
--- /dev/null
+../motion-hv/motionscan-hv.inc
\ No newline at end of file
+++ /dev/null
-../motion/motionscan.C
\ No newline at end of file
+++ /dev/null
-../motion/motionscan.h
\ No newline at end of file
+++ /dev/null
-../motion/motionscan.inc
\ No newline at end of file
#include "clip.h"
#include "interpolatevideo.h"
-#include "motionscan.h"
+#include "motionscan-hv.h"
#include "opticflow.h"
#include <sys/time.h>
#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
--- /dev/null
+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:
--- /dev/null
+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:
--- /dev/null
+../motion.la
\ No newline at end of file
--- /dev/null
+# 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'
--- /dev/null
+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
+
--- /dev/null
+
+/*
+ * 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;
+}
+
+
+
--- /dev/null
+
+/*
+ * 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;
+}
+
+
+
--- /dev/null
+
+/*
+ * 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
+
+
+
+
+
+
--- /dev/null
+
+/*
+ * 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;
+}
+
--- /dev/null
+
+/*
+ * 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;
+};
+
+
--- /dev/null
+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
/*
* 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.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"
#include <errno.h>
#include <unistd.h>
-REGISTER_PLUGIN(MotionMain)
+REGISTER_PLUGIN(MotionHVMain)
#undef DEBUG
-MotionConfig::MotionConfig()
+MotionHVConfig::MotionHVConfig()
{
global_range_w = 5;
global_range_h = 5;
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);
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 &&
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;
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;
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;
-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;
rotate_target_dst = 0;
}
-MotionMain::~MotionMain()
+MotionHVMain::~MotionHVMain()
{
delete engine;
delete [] search_area;
delete temp_frame;
delete rotate_engine;
- delete motion_rotate;
+// delete motion_rotate;
delete prev_global_ref;
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();
}
}
-void MotionMain::save_data(KeyFrame *keyframe)
+void MotionHVMain::save_data(KeyFrame *keyframe)
{
FileXML output;
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);
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);
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;
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);
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);
-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 ||
}
-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
// 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.
}
// 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;
}
- if(config.action_type != MotionScan::NOTHING)
+ if(config.action_type != MotionHVScan::NOTHING)
{
if(!overlayer)
overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
-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;
// 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();
// 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;
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
{
}
#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,
// 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() *
}
+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,
-int MotionMain::process_buffer(VFrame **frame,
+int MotionHVMain::process_buffer(VFrame **frame,
int64_t start_position,
double frame_rate)
{
#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
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)
}
- if(!config.global && !config.rotate) skip_current = 1;
+// if(!config.global && !config.rotate) skip_current = 1;
// 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.
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);
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);
}
-
+//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);
read_frame(frame[target_layer],
target_layer,
start_position,
- frame_rate);
+ frame_rate,
+ 0);
}
if(config.draw_vectors)
}
#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();
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 /
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 /
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,
// search_x2,
// search_y2);
- MotionScan::clamp_scan(w,
+ MotionHVScan::clamp_scan(w,
h,
&block_x1,
&block_y1,
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;
-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;
}
-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)
{
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;
-
-
-
-
-
-
-
-
-
-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;
-}
-
-
-
/*
* 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;
// 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);
// 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;
-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,
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);
// 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;
-
-
-
-
-
-
-
-
-
-
-
-
-
-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
*
*/
-#ifndef MOTION_INC
-#define MOTION_INC
+#ifndef MOTIONHV_INC
+#define MOTIONHV_INC
-class MotionConfig;
-class MotionMain;
+class MotionHVConfig;
+class MotionHVMain;
#endif
--- /dev/null
+
+/*
+ * 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);
+}
+
+
+
/*
* 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;
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
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();
// 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,
// OVERSAMPLE
int dx_result;
int dy_result;
+ float dr_result;
enum
{
};
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
// 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;
};
*
*/
-#ifndef MOTIONSCAN_INC
-#define MOTIONSCAN_INC
+#ifndef MOTIONSCANHV_INC
+#define MOTIONSCANHV_INC
-class MotionScan;
+class MotionHVScan;
/*
* 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
#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;
- 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));
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:")));
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));
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));
- 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,
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);
}
-GlobalRange::GlobalRange(MotionMain *plugin,
+GlobalRange::GlobalRange(MotionHVMain *plugin,
int x,
int y,
int *value)
-RotationRange::RotationRange(MotionMain *plugin,
+RotationRange::RotationRange(MotionHVMain *plugin,
int x,
int y)
: BC_IPot(x,
-RotationCenter::RotationCenter(MotionMain *plugin,
+RotationCenter::RotationCenter(MotionHVMain *plugin,
int x,
int y)
: BC_IPot(x,
-BlockSize::BlockSize(MotionMain *plugin,
+BlockSize::BlockSize(MotionHVMain *plugin,
int x,
int y,
int *value)
-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,
this->plugin = plugin;
}
-int MotionMagnitude::handle_event()
+int MotionHVMagnitude::handle_event()
{
plugin->config.magnitude = (int)get_value();
plugin->send_configure_change();
}
-MotionReturnSpeed::MotionReturnSpeed(MotionMain *plugin,
+MotionHVReturnSpeed::MotionHVReturnSpeed(MotionHVMain *plugin,
int x,
int y)
: BC_IPot(x,
this->plugin = plugin;
}
-int MotionReturnSpeed::handle_event()
+int MotionHVReturnSpeed::handle_event()
{
plugin->config.return_speed = (int)get_value();
plugin->send_configure_change();
-MotionRMagnitude::MotionRMagnitude(MotionMain *plugin,
+MotionHVRMagnitude::MotionHVRMagnitude(MotionHVMain *plugin,
int x,
int y)
: BC_IPot(x,
this->plugin = plugin;
}
-int MotionRMagnitude::handle_event()
+int MotionHVRMagnitude::handle_event()
{
plugin->config.rotate_magnitude = (int)get_value();
plugin->send_configure_change();
-MotionRReturnSpeed::MotionRReturnSpeed(MotionMain *plugin,
+MotionHVRReturnSpeed::MotionHVRReturnSpeed(MotionHVMain *plugin,
int x,
int y)
: BC_IPot(x,
this->plugin = plugin;
}
-int MotionRReturnSpeed::handle_event()
+int MotionHVRReturnSpeed::handle_event()
{
plugin->config.rotate_return_speed = (int)get_value();
plugin->send_configure_change();
-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,
this->gui = gui;
}
-int MotionRotate::handle_event()
+int MotionHVRotate::handle_event()
{
plugin->config.rotate = get_value();
plugin->send_configure_change();
-MotionBlockX::MotionBlockX(MotionMain *plugin,
- MotionWindow *gui,
+MotionHVBlockX::MotionHVBlockX(MotionHVMain *plugin,
+ MotionHVWindow *gui,
int x,
int y)
: BC_FPot(x,
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);
-MotionBlockY::MotionBlockY(MotionMain *plugin,
- MotionWindow *gui,
+MotionHVBlockY::MotionHVBlockY(MotionHVMain *plugin,
+ MotionHVWindow *gui,
int x,
int y)
: BC_FPot(x,
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);
return 1;
}
-MotionBlockXText::MotionBlockXText(MotionMain *plugin,
- MotionWindow *gui,
+MotionHVBlockXText::MotionHVBlockXText(MotionHVMain *plugin,
+ MotionHVWindow *gui,
int x,
int y)
: BC_TextBox(x,
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);
-MotionBlockYText::MotionBlockYText(MotionMain *plugin,
- MotionWindow *gui,
+MotionHVBlockYText::MotionHVBlockYText(MotionHVMain *plugin,
+ MotionHVWindow *gui,
int x,
int y)
: BC_TextBox(x,
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);
-MotionDrawVectors::MotionDrawVectors(MotionMain *plugin,
- MotionWindow *gui,
+MotionHVDrawVectors::MotionHVDrawVectors(MotionHVMain *plugin,
+ MotionHVWindow *gui,
int x,
int y)
: BC_CheckBox(x,
this->plugin = plugin;
}
-int MotionDrawVectors::handle_event()
+int MotionHVDrawVectors::handle_event()
{
plugin->config.draw_vectors = get_value();
plugin->send_configure_change();
-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;
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();
-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()
-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;
}
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();
-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;
}
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();
-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),
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)));
-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),
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;
}
-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),
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;
}
-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),
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)));
--- /dev/null
+
+/*
+ * 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;
+};
+
+
+
+
+
+
+
+
+
*
*/
-#ifndef MOTIONWINDOW_INC
-#define MOTIONWINDOW_INC
+#ifndef MOTIONWINDOWHV_INC
+#define MOTIONWINDOWHV_INC
-class MotionWindow;
-class MotionThread;
+class MotionHVWindow;
+class MotionHVThread;
#endif
+++ /dev/null
-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
+++ /dev/null
-
-/*
- * 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);
-}
-
-
-
+++ /dev/null
-
-/*
- * 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;
-};
-
-
-
-
-
-
-
-
-
/*
* 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
#include "mutex.h"
#include "overlayframe.h"
#include "rotateframe.h"
-#include "rotatescan.h"
#include "transportque.h"
REGISTER_PLUGIN(MotionMain)
+
#undef DEBUG
// #ifndef DEBUG
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);
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 &&
// 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 &&
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;
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;
{
engine = 0;
rotate_engine = 0;
-// motion_rotate = 0;
+ motion_rotate = 0;
total_dx = 0;
total_dy = 0;
total_angle = 0;
current_rotate_ref = 0;
rotate_target_src = 0;
rotate_target_dst = 0;
+
+ config.set_cpus(get_project_smp() + 1);
}
MotionMain::~MotionMain()
delete [] search_area;
delete temp_frame;
delete rotate_engine;
-// delete motion_rotate;
+ delete motion_rotate;
delete prev_global_ref;
{
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);
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("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);
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.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);
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;
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
// 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)
{
dx = -(int)(total_dx / OVERSAMPLE);
dy = -(int)(total_dy / OVERSAMPLE);
break;
+ break;
case MotionScan::TRACK:
interpolation = CUBIC_LINEAR;
dx = (float)total_dx / OVERSAMPLE;
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);
// 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)
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
{
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() *
}
-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,
}
-// if(!config.global && !config.rotate) skip_current = 1;
+ if(!config.global && !config.rotate) skip_current = 1;
// 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.
-//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);
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.
+
+
+
+
+
+
+
+
+
+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;
+}
+
+
+
/*
* 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;
// Precision of rotation
#define MIN_ANGLE 0.0001
+#define ROTATION_FILE "/tmp/r"
class MotionConfig
{
int64_t next_frame,
int64_t current_frame);
void boundaries();
+ void set_cpus(int cpus);
int block_count;
int global_range_w;
// 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;
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
// 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;
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
/*
* 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
/*
* 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()
: 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);
}
+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(
-// 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;
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.
case MotionScan::NO_CALCULATE:
dx_result = 0;
dy_result = 0;
- dr_result = rotation_center;
skip = 1;
break;
{
// 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;
}
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;
- 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,
// 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,
// 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,
&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.
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
// 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);
}
+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 difference; \
difference = *prev_row++ - *current_row++; \
- difference *= difference; \
- result_temp += difference; \
+ if(difference < 0) \
+ result_temp -= difference; \
+ else \
+ result_temp += difference; \
} \
if(components == 4) \
{ \
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;
}
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 */ \
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,
// 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;
}
if(*scan_x1 < 0)
{
int difference = -*scan_x1;
-#ifdef CLAMP_BLOCK
- *block_x1 += difference;
-#endif
+// *block_x1 += difference;
*scan_x2 += difference;
*scan_x1 = 0;
}
if(*scan_y1 < 0)
{
int difference = -*scan_y1;
-#ifdef CLAMP_BLOCK
- *block_y1 += difference;
-#endif
+// *block_y1 += difference;
*scan_y2 += difference;
*scan_y1 = 0;
}
{
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));
/*
* 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>
#define OVERSAMPLE 4
#define MOTION_FILE "/tmp/m"
-#define ROTATION_FILE "/tmp/r"
class MotionScanPackage : public LoadPackage
{
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;
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
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:
~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();
// 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,
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,
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
{
STABILIZE_PIXEL,
NOTHING
};
-
+
enum
{
// tracking_type
LOAD,
NO_CALCULATE
};
-
+
enum
{
// frame_type
};
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
// 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;
};
/*
* 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
-// 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,
// 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:")));
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,
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);
}
-// 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;
+}
+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)
-// 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,
/*
* 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 TrackSingleFrame : public BC_Radial
{
public:
- TrackSingleFrame(MotionMain *plugin,
+ TrackSingleFrame(MotionMain *plugin,
MotionWindow *gui,
- int x,
+ int x,
int y);
int handle_event();
MotionMain *plugin;
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;
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;
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;
class GlobalRange : public BC_IPot
{
public:
- GlobalRange(MotionMain *plugin,
- int x,
+ GlobalRange(MotionMain *plugin,
+ int x,
int y,
int *value);
int handle_event();
class RotationRange : public BC_IPot
{
public:
- RotationRange(MotionMain *plugin,
- int x,
+ RotationRange(MotionMain *plugin,
+ int x,
int y);
int handle_event();
MotionMain *plugin;
class RotationCenter : public BC_IPot
{
public:
- RotationCenter(MotionMain *plugin,
- int x,
+ RotationCenter(MotionMain *plugin,
+ int x,
int y);
int handle_event();
MotionMain *plugin;
class BlockSize : public BC_IPot
{
public:
- BlockSize(MotionMain *plugin,
- int x,
+ BlockSize(MotionMain *plugin,
+ int x,
int y,
int *value);
int handle_event();
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;
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;
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;
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;
class MotionRMagnitude : public BC_IPot
{
public:
- MotionRMagnitude(MotionMain *plugin,
- int x,
+ MotionRMagnitude(MotionMain *plugin,
+ int x,
int y);
int handle_event();
MotionMain *plugin;
class MotionReturnSpeed : public BC_IPot
{
public:
- MotionReturnSpeed(MotionMain *plugin,
- int x,
+ MotionReturnSpeed(MotionMain *plugin,
+ int x,
int y);
int handle_event();
MotionMain *plugin;
class MotionRReturnSpeed : public BC_IPot
{
public:
- MotionRReturnSpeed(MotionMain *plugin,
- int x,
+ MotionRReturnSpeed(MotionMain *plugin,
+ int x,
int y);
int handle_event();
MotionMain *plugin;
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;
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;
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;
/*
* 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
/*
* 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
- *
+ *
*/
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));
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);
/* 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))
{
vector<CvPoint2D32f> pt1, pt2;
CvMat _pt1, _pt2;
int i, n;
-
+
(*point_pairs) = 0;
(*total_pairs) = 0;
// 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];
int OpenCVWrapper::scan(VFrame *object_frame,
VFrame *scene_frame,
- int object_x1,
+ int object_x1,
int object_y1,
int object_x2,
int object_y2,
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))
{
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))
{
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);
}
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);
point_pairs = 0;
- cvExtractSURF(object_image,
- 0,
- &object_keypoints,
- &object_descriptors,
- storage,
+ cvExtractSURF(object_image,
+ 0,
+ &object_keypoints,
+ &object_descriptors,
+ storage,
params,
0);
// {
// 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);
// {
// 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 }
};
//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))
{
// 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,
/*
* 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
- *
+ *
*/
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,
// 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,
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));
+++ /dev/null
-
-/*
- * 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;
-}
-
-
-
+++ /dev/null
-
-/*
- * 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
-
-
-
-
-
+++ /dev/null
-#ifndef ROTATESCAN_INC
-#define ROTATESCAN_INC
-
-
-class RotateScan;
-
-
-#endif
-
-
-
-
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
*/
#include "affine.h"
-#include "../motion/motionscan.h"
+#include "../motion-hv/motionscan-hv.h"
#include "bcdisplayinfo.h"
#include "bcsignals.h"
#include "clip.h"
#include <string.h>
#include "affine.inc"
-#include "motionscan.inc"
+#include "motionscan-hv.inc"
#include "bchash.inc"
#include "filexml.inc"
#include "keyframe.inc"
--- /dev/null
+../motion-hv/motionscan-hv.C
\ No newline at end of file
--- /dev/null
+../motion-hv/motionscan-hv.h
\ No newline at end of file
--- /dev/null
+../motion-hv/motionscan-hv.inc
\ No newline at end of file
+++ /dev/null
-../motion/motionscan.C
\ No newline at end of file
+++ /dev/null
-../motion/motionscan.h
\ No newline at end of file
+++ /dev/null
-../motion/motionscan.inc
\ No newline at end of file
#include "clip.h"
#include "language.h"
#include "motion.h"
-#include "motionscan.h"
+#include "motionscan-hv.h"
#include "motionwindow.h"
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