merge hv v6, rework trace methods
authorGood Guy <good1.2guy@gmail.com>
Tue, 15 Nov 2016 19:28:25 +0000 (12:28 -0700)
committerGood Guy <good1.2guy@gmail.com>
Tue, 15 Nov 2016 19:28:25 +0000 (12:28 -0700)
70 files changed:
cinelerra-5.1/cinelerra/affine.C
cinelerra-5.1/cinelerra/affine.h
cinelerra-5.1/cinelerra/assetedit.C
cinelerra-5.1/cinelerra/assetpopup.C
cinelerra-5.1/cinelerra/assetpopup.h
cinelerra-5.1/cinelerra/batchrender.C
cinelerra-5.1/cinelerra/bdcreate.C
cinelerra-5.1/cinelerra/brender.C
cinelerra-5.1/cinelerra/browsebutton.C
cinelerra-5.1/cinelerra/browsebutton.h
cinelerra-5.1/cinelerra/dvdcreate.C
cinelerra-5.1/cinelerra/edlsession.C
cinelerra-5.1/cinelerra/edlsession.h
cinelerra-5.1/cinelerra/exportedl.C
cinelerra-5.1/cinelerra/filexml.h
cinelerra-5.1/cinelerra/formattools.C
cinelerra-5.1/cinelerra/interfaceprefs.C
cinelerra-5.1/cinelerra/loadbalance.C
cinelerra-5.1/cinelerra/main.C
cinelerra-5.1/cinelerra/mainmenu.C
cinelerra-5.1/cinelerra/mainmenu.h
cinelerra-5.1/cinelerra/mainsession.h
cinelerra-5.1/cinelerra/mwindow.C
cinelerra-5.1/cinelerra/mwindow.h
cinelerra-5.1/cinelerra/mwindow.inc
cinelerra-5.1/cinelerra/performanceprefs.C
cinelerra-5.1/cinelerra/performanceprefs.h
cinelerra-5.1/cinelerra/pluginclient.C
cinelerra-5.1/cinelerra/preferences.C
cinelerra-5.1/cinelerra/preferences.h
cinelerra-5.1/cinelerra/preferencesthread.C
cinelerra-5.1/cinelerra/recordgui.C
cinelerra-5.1/cinelerra/trackcanvas.C
cinelerra-5.1/cinelerra/trackcanvas.h
cinelerra-5.1/guicast/Makefile
cinelerra-5.1/guicast/bcsignals.C
cinelerra-5.1/guicast/bcsignals.h
cinelerra-5.1/guicast/bctrace.C [new file with mode: 0644]
cinelerra-5.1/guicast/bctrace.h [new file with mode: 0644]
cinelerra-5.1/guicast/bctrace.inc [new file with mode: 0644]
cinelerra-5.1/guicast/bctumble.C
cinelerra-5.1/guicast/bcwindowbase.C
cinelerra-5.1/guicast/bcwindowbase.h
cinelerra-5.1/guicast/clip.h
cinelerra-5.1/guicast/condition.C
cinelerra-5.1/guicast/condition.h
cinelerra-5.1/guicast/mutex.C
cinelerra-5.1/guicast/mutex.h
cinelerra-5.1/guicast/sema.C
cinelerra-5.1/guicast/sema.h
cinelerra-5.1/guicast/thread.C
cinelerra-5.1/guicast/vframe.C
cinelerra-5.1/guicast/vframe.h
cinelerra-5.1/plugins/interpolatevideo/interpolatevideo.C
cinelerra-5.1/plugins/interpolatevideo/opticflow.C
cinelerra-5.1/plugins/motion/debug [deleted file]
cinelerra-5.1/plugins/motion/motion.C
cinelerra-5.1/plugins/motion/motion.h
cinelerra-5.1/plugins/motion/motionscan.C
cinelerra-5.1/plugins/motion/motionscan.h
cinelerra-5.1/plugins/motion/motionwindow.C
cinelerra-5.1/plugins/motion/motionwindow.h
cinelerra-5.1/plugins/motion/rotatescan.C [new file with mode: 0644]
cinelerra-5.1/plugins/motion/rotatescan.h [new file with mode: 0644]
cinelerra-5.1/plugins/motion/rotatescan.inc [new file with mode: 0644]
cinelerra-5.1/plugins/motion2point/motion.C
cinelerra-5.1/plugins/reframert/reframert.C
cinelerra-5.1/plugins/resamplert/resamplert.C
cinelerra-5.1/plugins/resamplert/resamplert.h
cinelerra-5.1/plugins/rotate/rotate.C

index 32f630fc7ef3f2ba33e0e1cfae8623678b745e2d..f6bedb2e17b557631889ca79b20e49789d37c569 100644 (file)
@@ -300,24 +300,14 @@ void AffineUnit::calculate_matrix(
 
 }
 
-float AffineUnit::transform_cubic(float dx,
-                               float jm1,
-                               float j,
-                               float jp1,
-                               float jp2)
+static inline float transform_cubic(float dx,
+               float jm1, float j, float jp1, float jp2)
 {
 /* Catmull-Rom - not bad */
        float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
                       ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
                       ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
-// printf("%f %f %f %f %f\n",
-// result,
-// jm1,
-// j,
-// jp1,
-// jp2);
-
-
+// printf("%f %f %f %f %f\n", result, jm1, j, jp1, jp2);
        return result;
 }
 
@@ -882,8 +872,11 @@ void AffineUnit::process_package(LoadPackage *package)
        unsigned char **in_rows = (unsigned char**)server->input->get_rows();
        float round_factor = 0.0;
        if(sizeof(unsigned char) < 4) round_factor = 0.5;
+
        for(int y = ty1; y < ty2; y++)
        {
+//printf("AffineUnit::process_package %d y=%d tx1=%d tx2=%d ty1=%d ty2=%d\n", 
+//__LINE__, y, tx1, tx2, ty1, ty2);
                unsigned char *out_row = (unsigned char*)server->output->get_rows()[y];
 
                if(!interpolate)
index 46119e2b1e202b0128b175cdc5e8d9f3da7aa920..d03f6cd872fd97c33ae67761327045883a8d1690 100644 (file)
@@ -74,11 +74,7 @@ public:
                double out_x4,
                double out_y4,
                AffineMatrix *result);
-       float transform_cubic(float dx,
-       float jm1,
-       float j,
-       float jp1,
-       float jp2);
+//     float transform_cubic(float dx, float jm1, float j, float jp1, float jp2);
        AffineEngine *server;
 };
 
index 7854999d99f0e05d52f9a5a7a0bc719c38b6641b..0b77d919afc216fcf5260de5337f7df732edd324 100644 (file)
@@ -953,7 +953,7 @@ int AssetEditPathText::handle_event()
 AssetEditPath::AssetEditPath(MWindow *mwindow, AssetEditWindow *fwindow,
        BC_TextBox *textbox, int y, const char *text,
        const char *window_title, const char *window_caption)
- : BrowseButton(mwindow, fwindow, textbox, 310, y, text,
+ : BrowseButton(mwindow->theme, fwindow, textbox, 310, y, text,
        window_title, window_caption, 0)
 {
        this->fwindow = fwindow;
index 2744f21798684b61e3a15070e45c25e3466e9a46..12a51429690bf93d5d192d23c89efb5865f25dff 100644 (file)
@@ -59,7 +59,7 @@ AssetPopup::~AssetPopup()
 
 void AssetPopup::create_objects()
 {
-       add_item(format = new AssetListFormat(mwindow));
+//     add_item(format = new AssetListFormat(mwindow));
        add_item(info = new AssetPopupInfo(mwindow, this));
        add_item(new AssetPopupSort(mwindow, this));
        add_item(index = new AssetPopupBuildIndex(mwindow, this));
@@ -119,7 +119,7 @@ void AssetPopup::match_all()
 
 int AssetPopup::update()
 {
-       format->update();
+//     format->update();
        gui->collect_assets();
        return 0;
 }
index 0196bbbb14119f38bbbf55ecb59c6f06f2d4af6e..b68b379e1b52f3396ea4dcc148b7272ecd09bf54 100644 (file)
@@ -59,7 +59,7 @@ public:
        AssetPopupBuildIndex *index;
        AssetPopupView *view;
        AssetPopupViewWindow *view_window;
-       AssetListFormat *format;
+//     AssetListFormat *format;
 };
 
 class AssetPopupInfo : public BC_MenuItem
index a02a8cff87615b23942f0027ca8dca6a9135cc0c..28481baab61f6b3f98f718015625a3289e35fa42 100644 (file)
@@ -783,7 +783,7 @@ void BatchRenderGUI::create_objects()
                x, y, get_w()-x - 40, thread->get_current_edl())); 
        x =  x2 + edl_path_text->get_w();
        add_subwindow(edl_path_browse = new BrowseButton(
-               mwindow, this, edl_path_text, x, y, thread->get_current_edl(),
+               mwindow->theme, this, edl_path_text, x, y, thread->get_current_edl(),
                _("Input EDL"), _("Select an EDL to load:"), 0));
        y2 = y + edl_path_browse->get_h() + mwindow->theme->widget_border;
 
index dc10bbc0e067af7c1cf6f7aab2b97d827a5dc992..6a583db6474ab41157e34974ced85d123b81aabd 100644 (file)
@@ -651,7 +651,7 @@ void CreateBD_GUI::create_objects()
        tmp_x = x + title->get_w();  tmp_y = y;
        tmp_path = new CreateBD_TmpPath(this, tmp_x, tmp_y,  get_w()-tmp_x-35);
        add_subwindow(tmp_path);
-       btmp_path = new BrowseButton(thread->mwindow, this, tmp_path,
+       btmp_path = new BrowseButton(thread->mwindow->theme, this, tmp_path,
                tmp_x+tmp_path->get_w(), tmp_y, "/tmp",
                _("Work path"), _("Select a Work directory:"), 1);
        add_subwindow(btmp_path);
index 3a1e3f82e4c7e61d88af0a6c303170dbee5bd4d5..00888c9fe06420155430aef4b4cf6723ffd6c90f 100644 (file)
@@ -569,7 +569,9 @@ void BRenderThread::start()
                if(last_good < 0) last_good = last_contiguous;
                int start_frame = MIN(last_contiguous, last_good);
                start_frame = MAX(start_frame, brender_start);
-               int64_t end_frame = Units::round(command->edl->tracks->total_video_length() *
+//             int64_t end_frame = Units::round(command->edl->tracks->total_video_length() * 
+//                     command->edl->session->frame_rate);
+               int64_t end_frame = Units::round(command->edl->session->brender_end *
                        command->edl->session->frame_rate);
                if(end_frame < start_frame) end_frame = start_frame;
 
index 4d2e69b29554d8baf4f897fc4b18280bcfba2204..95f358db9945cdf2ac31b433e47fffa4b920f4b4 100644 (file)
@@ -2,42 +2,42 @@
 /*
  * 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 "bcsignals.h"
 #include "browsebutton.h"
 #include "language.h"
 #include "mutex.h"
-#include "mwindow.h"
 #include "theme.h"
 
 
 
 
-BrowseButton::BrowseButton(MWindow *mwindow,
-       BC_WindowBase *parent_window,
-       BC_TextBox *textbox,
-       int x,
-       int y,
-       const char *init_directory,
-       const char *title,
-       const char *caption,
+BrowseButton::BrowseButton(Theme *theme, 
+       BC_WindowBase *parent_window, 
+       BC_TextBox *textbox, 
+       int x, 
+       int y, 
+       const char *init_directory, 
+       const char *title, 
+       const char *caption, 
        int want_directory)
- : BC_Button(x, y, mwindow->theme->get_image_set("magnify_button")),
+ : BC_Button(x, y, theme->get_image_set("magnify_button")), 
    Thread(1, 0, 0)
 {
        this->parent_window = parent_window;
@@ -46,7 +46,7 @@ BrowseButton::BrowseButton(MWindow *mwindow,
        this->caption = caption;
        this->init_directory = init_directory;
        this->textbox = textbox;
-       this->mwindow = mwindow;
+       this->theme = theme;
        set_tooltip(_("Look for file"));
        gui = 0;
        startup_lock = new Mutex("BrowseButton::startup_lock");
@@ -91,16 +91,16 @@ int BrowseButton::handle_event()
 
 void BrowseButton::run()
 {
-       BrowseButtonWindow browsewindow(mwindow,
+       BrowseButtonWindow browsewindow(theme,
                this,
-               parent_window,
-               textbox->get_text(),
-               title,
-               caption,
+               parent_window, 
+               textbox->get_text(), 
+               title, 
+               caption, 
                want_directory);
        gui = &browsewindow;
        startup_lock->unlock();
-
+       
        browsewindow.lock_window("BrowseButton::run");
        browsewindow.create_objects();
        browsewindow.unlock_window();
@@ -130,22 +130,33 @@ void BrowseButton::run()
 }
 
 
-BrowseButtonWindow::BrowseButtonWindow(MWindow *mwindow,
+
+
+
+
+BrowseButtonWindow::BrowseButtonWindow(Theme *theme, 
        BrowseButton *button,
-       BC_WindowBase *parent_window,
-       const char *init_directory,
-       const char *title,
-       const char *caption,
+       BC_WindowBase *parent_window, 
+       const char *init_directory, 
+       const char *title, 
+       const char *caption, 
        int want_directory)
- : BC_FileBox(button->x - BC_WindowBase::get_resources()->filebox_w / 2,
-       button->y - BC_WindowBase::get_resources()->filebox_h / 2,
-       init_directory, title, caption,
-       want_directory, // Set to 1 to get hidden files.
-       want_directory, // Want only directories
-       0, mwindow->theme->browse_pad)
+ : BC_FileBox(button->x - 
+               BC_WindowBase::get_resources()->filebox_w / 2, 
+       button->y - 
+               BC_WindowBase::get_resources()->filebox_h / 2,
+       init_directory,
+       title,
+       caption,
+// Set to 1 to get hidden files. 
+       want_directory,
+// Want only directories
+       want_directory,
+       0,
+       theme->browse_pad)
 {
 }
 
-BrowseButtonWindow::~BrowseButtonWindow()
+BrowseButtonWindow::~BrowseButtonWindow() 
 {
 }
index ff8ece6f0eb6e9a72f23692e549f4fba242b063a..f88a352e87c753f810e4e5fb745d68938783746b 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "guicast.h"
 #include "mutex.inc"
-#include "mwindow.inc"
+#include "theme.inc"
 #include "thread.h"
 
 class BrowseButtonWindow;
@@ -32,14 +32,14 @@ class BrowseButtonWindow;
 class BrowseButton : public BC_Button, public Thread
 {
 public:
-       BrowseButton(MWindow *mwindow,
-               BC_WindowBase *parent_window,
-               BC_TextBox *textbox,
-               int x,
-               int y,
-               const char *init_directory,
-               const char *title,
-               const char *caption,
+       BrowseButton(Theme *theme, 
+               BC_WindowBase *parent_window, 
+               BC_TextBox *textbox, 
+               int x, 
+               int y, 
+               const char *init_directory, 
+               const char *title, 
+               const char *caption, 
                int want_directory = 0);
        ~BrowseButton();
 
@@ -51,7 +51,7 @@ public:
        const char *caption;
        const char *init_directory;
        BC_TextBox *textbox;
-       MWindow *mwindow;
+       Theme *theme;
        BC_WindowBase *parent_window;
        BrowseButtonWindow *gui;
        Mutex *startup_lock;
@@ -61,7 +61,7 @@ public:
 class BrowseButtonWindow : public BC_FileBox
 {
 public:
-       BrowseButtonWindow(MWindow *mwindow,
+       BrowseButtonWindow(Theme *theme,
                BrowseButton *button,
                BC_WindowBase *parent_window,
                const char *init_directory,
index c752ba812a8feda6437f8d59bf916157637fbcc1..f6a6bc699868017a6af2632e06934be592e8806b 100644 (file)
@@ -771,7 +771,7 @@ void CreateDVD_GUI::create_objects()
        tmp_x = x + title->get_w();  tmp_y = y;
        tmp_path = new CreateDVD_TmpPath(this, tmp_x, tmp_y,  get_w()-tmp_x-35);
        add_subwindow(tmp_path);
-       btmp_path = new BrowseButton(thread->mwindow, this, tmp_path,
+       btmp_path = new BrowseButton(thread->mwindow->theme, this, tmp_path,
                tmp_x+tmp_path->get_w(), tmp_y, "/tmp",
                _("Work path"), _("Select a Work directory:"), 1);
        add_subwindow(btmp_path);
index 0930dd0593b185b5c2f1b4136dd22dd03a2d83d5..ddce17f1b45dbd9c18a1b09ee0edcf928d6d58b5 100644 (file)
@@ -53,7 +53,7 @@ EDLSession::EDLSession(EDL *edl)
        audio_tracks = 2;
        autos_follow_edits = 1; // this is needed for predictability
        auto_keyframes = 0;
-       brender_start = 0.0;
+       brender_start = brender_end = 0.0;
        clipboard_length = 0; // unused
        color_model = BC_RGBA8888;
        interlace_mode = ILACE_MODE_UNDETECTED;
@@ -225,6 +225,7 @@ int EDLSession::load_defaults(BC_Hash *defaults)
        auto_conf->load_defaults(defaults);
        autos_follow_edits = defaults->get("AUTOS_FOLLOW_EDITS", 1);
        brender_start = defaults->get("BRENDER_START", brender_start);
+       brender_end = defaults->get("BRENDER_END", brender_end);
        BC_CModels::to_text(string, BC_RGBA8888);
        color_model = BC_CModels::from_text(defaults->get("COLOR_MODEL", string));
        eyedrop_radius = defaults->get("EYEDROP_RADIUS", 0);
@@ -372,6 +373,7 @@ int EDLSession::save_defaults(BC_Hash *defaults)
        defaults->update("ATRACKS", audio_tracks);
        defaults->update("AUTOS_FOLLOW_EDITS", autos_follow_edits);
        defaults->update("BRENDER_START", brender_start);
+       defaults->update("BRENDER_END", brender_end);
        BC_CModels::to_text(string, color_model);
        defaults->update("COLOR_MODEL", string);
        ilacemode_to_xmltext(string, interlace_mode);
@@ -516,6 +518,7 @@ void EDLSession::boundaries()
        Workarounds::clamp(ruler_y1, 0.0, output_h);
        Workarounds::clamp(ruler_y2, 0.0, output_h);
        if(brender_start < 0) brender_start = 0.0;
+       if(brender_end < 0) brender_end = 0.0;
 
        Workarounds::clamp(subtitle_number, 0, 31);
        Workarounds::clamp(awindow_folder, 0, AWINDOW_FOLDERS - 1);
@@ -595,6 +598,7 @@ int EDLSession::load_xml(FileXML *file,
                auto_keyframes = file->tag.get_property("AUTO_KEYFRAMES", auto_keyframes);
                autos_follow_edits = file->tag.get_property("AUTOS_FOLLOW_EDITS", autos_follow_edits);
                brender_start = file->tag.get_property("BRENDER_START", brender_start);
+               brender_end = file->tag.get_property("BRENDER_END", brender_end);
                eyedrop_radius = file->tag.get_property("EYEDROP_RADIUS", eyedrop_radius);
                crop_x1 = file->tag.get_property("CROP_X1", crop_x1);
                crop_y1 = file->tag.get_property("CROP_Y1", crop_y1);
@@ -668,6 +672,7 @@ int EDLSession::save_xml(FileXML *file)
        file->tag.set_property("AUTO_KEYFRAMES", auto_keyframes);
        file->tag.set_property("AUTOS_FOLLOW_EDITS", autos_follow_edits);
        file->tag.set_property("BRENDER_START", brender_start);
+       file->tag.set_property("BRENDER_END", brender_end);
        file->tag.set_property("EYEDROP_RADIUS", eyedrop_radius);
        file->tag.set_property("CROP_X1", crop_x1);
        file->tag.set_property("CROP_Y1", crop_y1);
@@ -797,6 +802,7 @@ int EDLSession::copy(EDLSession *session)
        audio_tracks = session->audio_tracks;
        autos_follow_edits = session->autos_follow_edits;
        brender_start = session->brender_start;
+       brender_end = session->brender_end;
        color_model = session->color_model;
        interlace_mode = session->interlace_mode;
        eyedrop_radius = session->eyedrop_radius;
index a919b1037b7c8165723e75f5577d4f9f04728466..81ef9fc5d14e341e3cb21f125fe7b3b39fdd5c07 100644 (file)
@@ -83,8 +83,9 @@ public:
        int autos_follow_edits;
 // Generate keyframes for every tweek
        int auto_keyframes;
-// Where to start background rendering
+// Where to do background rendering
        double brender_start;
+       double brender_end;
 // Length of clipboard if pasting
        double clipboard_length;
 // Colormodel for intermediate frames
index 45b9d408e01bb1442a63d5a6280e5b327124859d..9a5cd005e760972f331a71a8886fbcfb32344977 100644 (file)
@@ -406,15 +406,8 @@ void ExportEDLWindow::create_objects()
 
        x += 24;
        add_subwindow(path_button = new BrowseButton(
-               mwindow,
-               this,
-               path_textbox, 
-               x, 
-               y - 4, 
-               exportasset->path,
-               _("Output to file"),
-               _("Select a file to write to:"),
-               0));
+               mwindow->theme, this, path_textbox, x, y - 4, exportasset->path,
+               _("Output to file"), _("Select a file to write to:"), 0));
        
        y += 34;
        x = 5;
index 270b763df7b29bf8e7533545c954cc8552ec42cd..4cff675866c22510f115fcba962491ba5e8bb8c3 100644 (file)
@@ -100,6 +100,7 @@ public:
        int64_t get_property(const char *property, int64_t default_);
        float get_property(const char *property, float default_);
        double get_property(const char *property, double default_);
+       const char* get_property_text(const char *property);
 
        int set_title(const char *text);
        int set_property(const char *text, const char *value);
index d6f275993e225a44b32a7353b4cf26a8ff96678d..60295e4b46c76088d288a191b5cf9f3928e5c492 100644 (file)
@@ -188,7 +188,7 @@ void FormatTools::create_objects(int &init_x,
                path_recent->load_items(File::formattostr(asset->format));
                px += path_recent->get_w() + 8;
                window->add_subwindow(path_button = new BrowseButton(
-                       mwindow, window, path_textbox, px, y, asset->path,
+                       mwindow->theme, window, path_textbox, px, y, asset->path,
                        _("Output to file"), _("Select a file to write to:"), 0));
 
 // Set w for user.
index 8df5e9938278be2b48a13465183abd00aadcd92c..f8600a5d22ca20b69527ed972834fc2cf9113eaf 100644 (file)
@@ -156,8 +156,7 @@ void InterfacePrefs::create_objects()
        add_subwindow(ipathtext = new IndexPathText(x + 230, y, 
                pwindow, 
                pwindow->thread->preferences->index_directory));
-       add_subwindow(ipath = new BrowseButton(mwindow, this,
-               ipathtext, 
+       add_subwindow(ipath = new BrowseButton(mwindow->theme, this, ipathtext, 
                x + 230 + ipathtext->get_w(), y, 
                pwindow->thread->preferences->index_directory,
                _("Index Path"), 
index 5765e39832cd5d23f4078cdfae4b5dc4b4dced18..fb8005bd3c7b56773b4d2bcb917e1b0d73ac81bd 100644 (file)
@@ -46,7 +46,6 @@ LoadPackage::~LoadPackage()
 LoadClient::LoadClient(LoadServer *server)
  : Thread(1, 0, 0)
 {
-       Thread::set_synchronous(1);
        this->server = server;
        done = 0;
        package_number = 0;
@@ -57,7 +56,6 @@ LoadClient::LoadClient(LoadServer *server)
 LoadClient::LoadClient()
  : Thread(1, 0, 0)
 {
-       Thread::set_synchronous(1);
        server = 0;
        done = 0;
        package_number = 0;
index f54edcec0b904d6bb38b65187af9e0fea35d8684..caa04a83b69af29295eb7d2974fcb2d095f90928 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#if 0
+#define STRC printf("==new %jd from %p\n", n, __builtin_return_address(0));
+void *operator new(size_t n) { STRC void *vp = malloc(n); bzero(vp,n); return vp; }
+void operator delete(void *t) { free(t); }
+void operator delete(void *t,size_t n) { free(t); }
+void *operator new[](size_t n) { STRC void *vp = malloc(n); bzero(vp,n); return vp; }
+void operator delete[](void *t) { free(t); }
+void operator delete[](void *t,size_t n) { free(t); }
+#endif
+
 enum
 {
        DO_GUI,
index 5542b49948405b583778d938ddf97244dd6e1b04..06a12becdb551f45533a07bd5d9217eb8637570c 100644 (file)
@@ -212,7 +212,7 @@ void MainMenu::create_objects()
        settingsmenu->add_item(new BC_MenuItem("-"));
        settingsmenu->add_item(new SaveSettingsNow(mwindow));
        settingsmenu->add_item(loop_playback = new LoopPlayback(mwindow));
-       settingsmenu->add_item(new SetBRenderStart(mwindow));
+       settingsmenu->add_item(new SetBRenderRange(mwindow));
 // set scrubbing speed
 //     ScrubSpeed *scrub_speed;
 //     settingsmenu->add_item(scrub_speed = new ScrubSpeed(mwindow));
@@ -1241,15 +1241,15 @@ int PasteSubttl::handle_event()
 
 
 
-SetBRenderStart::SetBRenderStart(MWindow *mwindow)
- : BC_MenuItem(_("Set background render"))
+SetBRenderRange::SetBRenderRange(MWindow *mwindow)
+ : BC_MenuItem(_("Set background rendering"))
 {
        this->mwindow = mwindow;
 }
 
-int SetBRenderStart::handle_event()
+int SetBRenderRange::handle_event()
 {
-       mwindow->set_brender_start();
+       mwindow->set_brender_range();
        return 1;
 }
 
index 25e20a1a014781a77165f80a0f99e88216dd2f70..ebbd208bf2af4240c044900d8ea7e391fcd7f5ad 100644 (file)
@@ -554,10 +554,10 @@ public:
        MWindow *mwindow;
 };
 
-class SetBRenderStart : public BC_MenuItem
+class SetBRenderRange : public BC_MenuItem
 {
 public:
-       SetBRenderStart(MWindow *mwindow);
+       SetBRenderRange(MWindow *mwindow);
        int handle_event();
        MWindow *mwindow;
 };
index e68938d997711a9d310b55a300cda688bf485da8..de08e5aae9a56f2ea2327ae96067bfd3723f574a 100644 (file)
@@ -100,7 +100,7 @@ public:
 // Value of keyframe when button was pressed
        float drag_start_percentage;
        long drag_start_position;
-// Records for redrawing brender position in timebar
+// Amount of data rendered, for drawing status in timebar
        double brender_end;
 // Position of cursor in CWindow output.  Used by ruler.
        int cwindow_output_x, cwindow_output_y;
index 5528477892299adf8d43b9c6d847cd705403d5c4..4884c641fa4383242efe4f63a9ddb7f6c4381343 100644 (file)
@@ -29,6 +29,7 @@
 #include "bcdisplayinfo.h"
 #include "bcsignals.h"
 #include "bctimer.h"
+#include "bctrace.h"
 #include "bdcreate.h"
 #include "brender.h"
 #include "cache.h"
@@ -788,6 +789,12 @@ void MWindow::init_preferences()
        BC_Signals::set_trap_hook(trap_hook, this);
        BC_Signals::set_catch_segv(preferences->trap_sigsegv);
        BC_Signals::set_catch_intr(preferences->trap_sigintr);
+       if( preferences->trap_sigsegv || preferences->trap_sigintr ) {
+               BC_Trace::enable_locks();
+       }
+       else {
+               BC_Trace::disable_locks();
+       }
        BC_WindowBase::get_resources()->popupmenu_btnup = preferences->popupmenu_btnup;
 }
 
@@ -1164,9 +1171,16 @@ int MWindow::brender_available(int position)
        return result;
 }
 
-void MWindow::set_brender_start()
+void MWindow::set_brender_range()
 {
        edl->session->brender_start = edl->local_session->get_selectionstart(1);
+       edl->session->brender_end = edl->local_session->get_selectionend(1);
+
+       if(EQUIV(edl->session->brender_end, edl->session->brender_start))
+       {
+               edl->session->brender_end = edl->tracks->total_video_length();
+       }
+
        restart_brender();
        gui->draw_overlays(1);
 }
index 39591eecafea84388e8886e7ca153dc81bddcc56..a6fd6e556877e29850561cb51793664a5fdc3076 100644 (file)
@@ -621,7 +621,7 @@ public:
 // This one happens asynchronously of the others.  Used by playback to
 // see what frame is background rendered.
        int brender_available(int position);
-       void set_brender_start();
+       void set_brender_range();
        int put_commercial();
        void activate_commercial() { commercial_active = 1; }
        void commit_commercial();
index 0d4975b14210c75d7b822368e795ccea671caa1d..74589a41fcc09039e7c766c3b2f9daf8c6749335 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 1997-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
index 99268702d7d63c42745c1be72776508c3a615dea..84672769fc7251ea6bba1c4323772e17999eccbe 100644 (file)
@@ -100,15 +100,22 @@ void PerformancePrefs::create_objects()
                maxw,
                ybx[1]);
        preroll->create_objects();
+       int x1 = preroll->get_x() + preroll->get_w() + 20;
+       BC_Title *smp_title = new BC_Title(x1, y + 5, _("Project SMP cpus:"));
+       add_subwindow(smp_title);
+       int x2 = x1 + smp_title->get_w() + 5;
+       PrefsProjectSMP *proj_smp = new PrefsProjectSMP(pwindow, this, x2, y);
+       proj_smp->create_objects();
+       
        y += 30;
        PrefsForceUniprocessor *force_1cpu = new PrefsForceUniprocessor(pwindow, x, y);
        add_subwindow(force_1cpu);
 
-       int x1 = force_1cpu->get_x() + force_1cpu->get_w() + 100;
+       x1 = force_1cpu->get_x() + force_1cpu->get_w() + 120;
 
        PrefsTrapSigSEGV *trap_segv = new PrefsTrapSigSEGV(this, x1, y);
        add_subwindow(trap_segv);
-       int x2 = x1 + trap_segv->get_w() + 10;
+       x2 = x1 + trap_segv->get_w() + 10;
        add_subwindow(new BC_Title(x2, y, _("(must be root)"), MEDIUMFONT, RED));
        y += 30;
 
@@ -861,6 +868,25 @@ int PrefsRenderFarmReset::handle_event()
 
 
 
+PrefsProjectSMP::PrefsProjectSMP(PreferencesWindow *pwindow,
+               PerformancePrefs *subwindow, int x, int y)
+ : BC_TumbleTextBox(subwindow,
+       (int64_t)pwindow->thread->preferences->project_smp,
+       (int64_t)1, (int64_t)100, x, y, 100)
+{
+       this->pwindow = pwindow;
+}
+PrefsProjectSMP::~PrefsProjectSMP()
+{
+}
+int PrefsProjectSMP::handle_event()
+{
+       pwindow->thread->preferences->project_smp = atol(get_text());
+       return 1;
+}
+
+
+
 
 
 PrefsRenderFarmJobs::PrefsRenderFarmJobs(PreferencesWindow *pwindow,
index dc02a2144e93507a0c11cc7774aa689494f1f6d7..ecedd28eb641d6ad78d8d3869a528b80952e3238 100644 (file)
@@ -209,6 +209,17 @@ public:
        PreferencesWindow *pwindow;
 };
 
+class PrefsProjectSMP : public BC_TumbleTextBox
+{
+public:
+       PrefsProjectSMP(PreferencesWindow *pwindow, 
+               PerformancePrefs *subwindow, int x, int y);
+       ~PrefsProjectSMP();
+       
+       int handle_event();
+       PreferencesWindow *pwindow;
+};
+
 class PrefsRenderFarmJobs : public BC_TumbleTextBox
 {
 public:
index 0e0637b734036cdf06c47459f60b524b8cc1d9c8..731d94e39f1b815a31d983c5a18f3ce4d8e87431 100644 (file)
@@ -186,7 +186,7 @@ PluginClient::PluginClient(PluginServer *server)
 {
        reset();
        this->server = server;
-       smp = server->preferences->processors;
+       smp = server->preferences->project_smp;
        defaults = 0;
        update_timer = new Timer;
 // Virtual functions don't work here.
index 5922414cc3bc8fa7a959cb7053173e4d3a49b196..e7fa696e893c9bc10a685df8d1b5804df31e1ad8 100644 (file)
@@ -75,7 +75,7 @@ Preferences::Preferences()
        renderfarm_mountpoint[0] = 0;
        renderfarm_vfs = 0;
        renderfarm_job_count = 20;
-       processors = calculate_processors(0);
+       project_smp = processors = calculate_processors(0);
        real_processors = calculate_processors(1);
        ffmpeg_early_probe = 0;
        ffmpeg_marker_indexes = 1;
@@ -179,6 +179,7 @@ void Preferences::copy_from(Preferences *that)
        for( int i=0; i<that->shbtn_prefs.size(); ++i )
                this->shbtn_prefs.append(new ShBtnPref(*that->shbtn_prefs[i]));
        cache_size = that->cache_size;
+       project_smp = that->project_smp;
        force_uniprocessor = that->force_uniprocessor;
        trap_sigsegv = that->trap_sigsegv;
        trap_sigintr = that->trap_sigintr;
@@ -332,6 +333,7 @@ int Preferences::load_defaults(BC_Hash *defaults)
 
 
 
+       project_smp = defaults->get("PROJECT_SMP", project_smp);
        force_uniprocessor = defaults->get("FORCE_UNIPROCESSOR", force_uniprocessor);
        ffmpeg_early_probe = defaults->get("FFMPEG_EARLY_PROBE", ffmpeg_early_probe);
        ffmpeg_marker_indexes = defaults->get("FFMPEG_MARKER_INDEXES", ffmpeg_marker_indexes);
@@ -435,6 +437,7 @@ int Preferences::save_defaults(BC_Hash *defaults)
                defaults->update(string, string2);
        }
 
+       defaults->update("PROJECT_SMP", project_smp);
        defaults->update("FORCE_UNIPROCESSOR", force_uniprocessor);
        defaults->update("FFMPEG_EARLY_PROBE", ffmpeg_early_probe);
        defaults->update("FFMPEG_MARKER_INDEXES", ffmpeg_marker_indexes);
index d2c21fc51a3506577d8f73967ffc17ef90db9e2b..d6f1821d57a27f8ecaeb50ea4f595d7e77ea300d 100644 (file)
@@ -93,6 +93,7 @@ public:
        double render_preroll;
        int brender_preroll;
        int force_uniprocessor;
+       int project_smp;
 // The number of cpus to use when rendering.
 // Determined by /proc/cpuinfo and force_uniprocessor
        int processors;
index 26c92c56e6bb37a0dc7cfb6df238a1f21554bfb1..a7a8287327148f1a363205896b9e904892193184 100644 (file)
@@ -23,6 +23,7 @@
 #include "asset.h"
 #include "audiodevice.inc"
 #include "bcsignals.h"
+#include "bctrace.h"
 #include "cache.h"
 #include "cplayback.h"
 #include "cwindow.h"
@@ -219,6 +220,12 @@ int PreferencesThread::apply_settings()
        BC_Signals::set_catch_segv(mwindow->preferences->trap_sigsegv);
        BC_Signals::set_catch_intr(mwindow->preferences->trap_sigintr);
        BC_WindowBase::get_resources()->popupmenu_btnup = mwindow->preferences->popupmenu_btnup;
+       if( mwindow->preferences->trap_sigsegv || mwindow->preferences->trap_sigintr ) {
+               BC_Trace::enable_locks();
+       }
+       else {
+               BC_Trace::disable_locks();
+       }
 
        mwindow->reset_android_remote();
        mwindow->gui->ffmpeg_toggle->update(mwindow->preferences->ffmpeg_early_probe);
index 64e2984f805d515f81de3475deb7dbdacd4c418b..2fa5d3f1f912ba5d3d583e7c0286daa8b6f9d893 100644 (file)
@@ -180,7 +180,7 @@ void RecordGUI::create_objects()
        y = 10;
        x = x1 + 20;
        add_subwindow(batch_path = new RecordPath(this, x, y));
-       add_subwindow(batch_browse = new BrowseButton(mwindow, 
+       add_subwindow(batch_browse = new BrowseButton(mwindow->theme
                this, 
                batch_path, 
                batch_path->get_x() + batch_path->get_w(), 
index 9ec6971bdb9f1aa58ee29311989aee3d03d64951..87e6f0747606343d7fca48030254797ee135ca45 100644 (file)
@@ -1852,19 +1852,28 @@ void TrackCanvas::draw_loop_points()
 //printf("TrackCanvas::draw_loop_points 7\n");
 }
 
-void TrackCanvas::draw_brender_start()
+void TrackCanvas::draw_brender_range()
 {
        if(mwindow->preferences->use_brender)
        {
-               int64_t x = Units::round(mwindow->edl->session->brender_start *
+               int64_t x1 = Units::round(mwindow->edl->session->brender_start *
                        mwindow->edl->session->sample_rate /
-                       mwindow->edl->local_session->zoom_sample -
+                       mwindow->edl->local_session->zoom_sample - 
+                       mwindow->edl->local_session->view_start[pane->number]);
+               if(MWindowGUI::visible(x1, x1 + 1, 0, get_w()))
+               {
+                       set_color(RED);
+                       draw_line(x1, 0, x1, get_h());
+               }
+               int64_t x2 = Units::round(mwindow->edl->session->brender_end *
+                       mwindow->edl->session->sample_rate /
+                       mwindow->edl->local_session->zoom_sample - 
                        mwindow->edl->local_session->view_start[pane->number]);
 
-               if(MWindowGUI::visible(x, x + 1, 0, get_w()))
+               if(MWindowGUI::visible(x2, x2 + 1, 0, get_w()))
                {
                        set_color(RED);
-                       draw_line(x, 0, x, get_h());
+                       draw_line(x2, 0, x2, get_h());
                }
        }
 }
@@ -3410,7 +3419,7 @@ void TrackCanvas::draw_overlays()
 
 // Loop points
        draw_loop_points();
-       draw_brender_start();
+       draw_brender_range();
 
 // Highlighted areas
        draw_highlighting();
index 9f86d81d3e1c83439c8b362bc0675f5aba84c7fe..c7b7f8463decc834c96c02a0a43f7663691baf77 100644 (file)
@@ -259,7 +259,7 @@ public:
        void synchronize_autos(float change, Track *skip, FloatAuto *fauto, int fill_gangs);
 
 
-       void draw_brender_start();
+       void draw_brender_range();
        void draw_loop_points();
        void draw_transitions();
        void draw_drag_handle();
index 613aba1db41ef00f333a7d9683782e60da7f1b11..efc7f15c1bbc6e06861b7a42b1808b1c2a7ef358 100644 (file)
@@ -57,6 +57,7 @@ OBJS = \
        $(OBJDIR)/bctheme.o \
        $(OBJDIR)/bctitle.o \
        $(OBJDIR)/bctoggle.o \
+       $(OBJDIR)/bctrace.o \
        $(OBJDIR)/bctumble.o \
        $(OBJDIR)/bcwindow.o \
        $(OBJDIR)/bcwindow3d.o \
@@ -69,7 +70,6 @@ OBJS = \
        $(OBJDIR)/filesystem.o \
        $(OBJDIR)/mutex.o \
        $(OBJDIR)/rotateframe.o \
-       $(OBJDIR)/sema.o \
        $(OBJDIR)/thread.o \
        $(OBJDIR)/testobject.o \
        $(OBJDIR)/bctimer.o \
index e7c14074e9715ac69e4e2eae408f8f605fd9b08c..e1e5aa38104a588cc42a56d5555fb103dded0bcd 100644 (file)
@@ -24,6 +24,7 @@
 #include "bccmodels.h"
 #include "bckeyboard.h"
 #include "bcresources.h"
+#include "cstrdup.h"
 
 #include <ctype.h>
 #include <dirent.h>
 
 BC_Signals* BC_Signals::global_signals = 0;
 static int signal_done = 0;
-static int table_id = 0;
-
-static bc_locktrace_t* new_bc_locktrace(void *ptr,
-       const char *title,
-       const char *location)
-{
-       bc_locktrace_t *result = (bc_locktrace_t*)malloc(sizeof(bc_locktrace_t));
-       result->ptr = ptr;
-       result->title = title;
-       result->location = location;
-       result->is_owner = 0;
-       result->id = table_id++;
-       result->tid = pthread_self();
-       return result;
-}
-
 
 static struct sigaction old_segv = {0, }, old_intr = {0, };
 static void handle_dump(int n, siginfo_t * info, void *sc);
@@ -113,22 +98,6 @@ void BC_Signals::set_catch_intr(bool v) {
        v = trap_sigintr;
 }
 
-typedef struct
-{
-       int size;
-       void *ptr;
-       const char *location;
-} bc_buffertrace_t;
-
-static bc_buffertrace_t* new_bc_buffertrace(int size, void *ptr, const char *location)
-{
-       bc_buffertrace_t *result = (bc_buffertrace_t*)malloc(sizeof(bc_buffertrace_t));
-       result->size = size;
-       result->ptr = ptr;
-       result->location = location;
-       return result;
-}
-
 static void bc_copy_textfile(int lines, FILE *ofp, const char *fmt,...)
 {
        va_list ap;    va_start(ap, fmt);
@@ -140,93 +109,8 @@ static void bc_copy_textfile(int lines, FILE *ofp, const char *fmt,...)
        fclose(ifp);
 }
 
-
-// Need our own table to avoid recursion with the memory manager
-typedef struct
-{
-       void **values;
-       int size;
-       int allocation;
-// This points to the next value to replace if the table wraps around
-       int current_value;
-} bc_table_t;
-
-static void* append_table(bc_table_t *table, void *ptr)
-{
-       if(table->allocation <= table->size)
-       {
-               if(table->allocation)
-               {
-                       int new_allocation = table->allocation * 2;
-                       void **new_values = (void**)calloc(new_allocation, sizeof(void*));
-                       memcpy(new_values, table->values, sizeof(void*) * table->size);
-                       free(table->values);
-                       table->values = new_values;
-                       table->allocation = new_allocation;
-               }
-               else
-               {
-                       table->allocation = 4096;
-                       table->values = (void**)calloc(table->allocation, sizeof(void*));
-               }
-       }
-
-       table->values[table->size++] = ptr;
-       return ptr;
-}
-
-// Replace item in table pointed to by current_value and advance
-// current_value
-static void* overwrite_table(bc_table_t *table, void *ptr)
-{
-       free(table->values[table->current_value]);
-       table->values[table->current_value++] = ptr;
-       if(table->current_value >= table->size) table->current_value = 0;
-       return 0;
-}
-
-static void clear_table(bc_table_t *table, int delete_objects)
-{
-       if(delete_objects)
-       {
-               for(int i = 0; i < table->size; i++)
-               {
-                       free(table->values[i]);
-               }
-       }
-       table->size = 0;
-}
-
-static void clear_table_entry(bc_table_t *table, int number, int delete_object)
-{
-       if(delete_object) free(table->values[number]);
-       for(int i = number; i < table->size - 1; i++)
-       {
-               table->values[i] = table->values[i + 1];
-       }
-       table->size--;
-}
-
-// Table of functions currently running.
-static bc_table_t execution_table = { 0, 0, 0, 0 };
-
-// Table of locked positions
-static bc_table_t lock_table = { 0, 0, 0, 0 };
-
-// Table of buffers
-static bc_table_t memory_table = { 0, 0, 0, 0 };
-
-static bc_table_t temp_files = { 0, 0, 0, 0 };
-
 // Can't use Mutex because it would be recursive
-static pthread_mutex_t *lock = 0;
 static pthread_mutex_t *handler_lock = 0;
-// incase lock set after task ends
-static pthread_t last_lock_thread = 0;
-static const char *last_lock_title = 0;
-static const char *last_lock_location = 0;
-// Don't trace memory until this is true to avoid initialization
-static int trace_memory = 0;
 
 
 static const char* signal_titles[] =
@@ -265,94 +149,45 @@ void BC_Signals::dump_stack(FILE *fp)
 void BC_Signals::kill_subs()
 {
 // List /proc directory
-       DIR *dirstream;
        struct dirent64 *new_filename;
        struct stat ostat;
-       char path[BCTEXTLEN];
-       char string[BCTEXTLEN];
-
-       dirstream = opendir("/proc");
-       if(!dirstream) return;
+       char path[BCTEXTLEN], string[BCTEXTLEN];
+       DIR *dirstream = opendir("/proc");
+       if( !dirstream ) return;
+       pid_t ppid = getpid();
 
-       while( (new_filename = readdir64(dirstream)) != 0 )
-       {
-// All digits are numbers
+       while( (new_filename = readdir64(dirstream)) != 0 ) {
                char *ptr = new_filename->d_name;
-               int got_alpha = 0;
-               while(*ptr)
-               {
-                       if(*ptr == '.' || isalpha(*ptr++))
-                       {
-                               got_alpha = 1;
-                               break;
-                       }
-               }
-
-               if(got_alpha) continue;
+               while( *ptr && *ptr != '.' && !isalpha(*ptr) ) ++ptr;
+// All digits are numbers
+               if( *ptr ) continue;
 
 // Must be a directory
                sprintf(path, "/proc/%s", new_filename->d_name);
-               if(!stat(path, &ostat))
-               {
-                       if(S_ISDIR(ostat.st_mode))
-                       {
-// Read process stat
-                               strcat(path, "/stat");
-//printf("kill_subs %d %s\n", __LINE__, path);
-                               FILE *fd = fopen(path, "r");
-
-// Must search forwards because the file is 0 length
-                               if(fd)
-                               {
-                                       while(!feof(fd))
-                                       {
-                                               char c = fgetc(fd);
+               if( stat(path, &ostat) ) continue;
+               if( !S_ISDIR(ostat.st_mode) ) continue;
+               strcat(path, "/stat");
+               FILE *fd = fopen(path, "r");
+               if( !fd ) continue;
+               while( !feof(fd) && fgetc(fd)!=')' );
 //printf("kill_subs %d %d\n", __LINE__, c);
-                                               if(c == ')')
-                                               {
-// Search for 2 spaces
-                                                       int spaces = 0;
-                                                       while(!feof(fd) && spaces < 2)
-                                                       {
-                                                               c = fgetc(fd);
-                                                               if(c == ' ')
-                                                                       spaces++;
-                                                       }
-
+               for( int sp=2; !feof(fd) && sp>0; )
+                       if( fgetc(fd) == ' ' ) --sp;
 // Read in parent process
-                                                       ptr = string;
-                                                       while(!feof(fd))
-                                                       {
-                                                               *ptr = fgetc(fd);
-                                                               if(*ptr == ' ')
-                                                               {
-                                                                       *ptr = 0;
-                                                                       break;
-                                                               }
-                                                               ptr++;
-                                                       }
+               for( ptr=string; !feof(fd) && (*ptr=fgetc(fd))!=' '; ++ptr );
+                       if( (*ptr=fgetc(fd)) == ' ' ) break;
+               *ptr = 0;
 
 // printf("kill_subs %d process=%d getpid=%d parent_process=%d\n",
-// __LINE__,
-// atoi(new_filename->d_name),
-// getpid(),
-// atoi(string));
-                                                       int parent_process = atoi(string);
-                                                       int child_process = atoi(new_filename->d_name);
-
+// __LINE__, atoi(new_filename->d_name), getpid(), atoi(string));
+               int parent_process = atoi(string);
 // Kill if we're the parent
-                                                       if(getpid() == parent_process)
-                                                       {
+               if( ppid == parent_process ) {
+                       int child_process = atoi(new_filename->d_name);
 //printf("kill_subs %d: process=%d\n", __LINE__, atoi(new_filename->d_name));
-                                                               kill(child_process, SIGKILL);
-                                                       }
-                                               }
-                                       }
-
-                                       fclose(fd);
-                               }
-                       }
+                       kill(child_process, SIGKILL);
                }
+               fclose(fd);
        }
 }
 
@@ -361,26 +196,19 @@ static void signal_entry(int signum)
        signal(signum, SIG_DFL);
 
        pthread_mutex_lock(handler_lock);
-       if(signal_done)
-       {
-               pthread_mutex_unlock(handler_lock);
-               exit(0);
-       }
-
+       int done = signal_done;
        signal_done = 1;
        pthread_mutex_unlock(handler_lock);
-
+       if( done ) exit(0);
 
        printf("signal_entry: got %s my pid=%d execution table size=%d:\n",
-               signal_titles[signum],
-               getpid(),
-               execution_table.size);
+               signal_titles[signum], getpid(), execution_table.size);
 
        BC_Signals::kill_subs();
-       BC_Signals::dump_traces();
-       BC_Signals::dump_locks();
-       BC_Signals::dump_buffers();
-       BC_Signals::delete_temps();
+       BC_Trace::dump_traces();
+       BC_Trace::dump_locks();
+       BC_Trace::dump_buffers();
+       BC_Trace::delete_temps();
 
 // Call user defined signal handler
        BC_Signals::global_signals->signal_handler(signum);
@@ -426,84 +254,6 @@ BC_Signals::~BC_Signals()
   BC_CModels::bcxfer_stop_slicers();
 }
 
-void BC_Signals::dump_traces(FILE *fp)
-{
-// Dump trace table
-       if(execution_table.size)
-       {
-               for(int i = execution_table.current_value; i < execution_table.size; i++)
-                       fprintf(fp,"    %s\n", (char*)execution_table.values[i]);
-               for(int i = 0; i < execution_table.current_value; i++)
-                       fprintf(fp,"    %s\n", (char*)execution_table.values[i]);
-       }
-
-}
-
-void BC_Signals::dump_locks(FILE *fp)
-{
-// Dump lock table
-#ifdef TRACE_LOCKS
-       fprintf(fp,"signal_entry: lock table size=%d\n", lock_table.size);
-       for(int i = 0; i < lock_table.size; i++)
-       {
-               bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
-               fprintf(fp,"    %p %s %s %p%s\n", table->ptr,
-                       table->title, table->location, (void*)table->tid,
-                       table->is_owner ? " *" : "");
-       }
-#endif
-}
-
-void BC_Signals::dump_buffers(FILE *fp)
-{
-#ifdef TRACE_MEMORY
-       pthread_mutex_lock(lock);
-// Dump buffer table
-       fprintf(fp,"BC_Signals::dump_buffers: buffer table size=%d\n", memory_table.size);
-       for(int i = 0; i < memory_table.size; i++)
-       {
-               bc_buffertrace_t *entry = (bc_buffertrace_t*)memory_table.values[i];
-               fprintf(fp,"    %d %p %s\n", entry->size, entry->ptr, entry->location);
-       }
-       pthread_mutex_unlock(lock);
-#endif
-}
-
-void BC_Signals::delete_temps()
-{
-       pthread_mutex_lock(lock);
-       if(temp_files.size) printf("BC_Signals::delete_temps: deleting %d temp files\n", temp_files.size);
-       for(int i = 0; i < temp_files.size; i++)
-       {
-               printf("    %s\n", (char*)temp_files.values[i]);
-               remove((char*)temp_files.values[i]);
-       }
-       pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::reset_locks()
-{
-       pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::set_temp(char *string)
-{
-       char *new_string = strdup(string);
-       append_table(&temp_files, new_string);
-}
-
-void BC_Signals::unset_temp(char *string)
-{
-       for(int i = 0; i < temp_files.size; i++)
-       {
-               if(!strcmp((char*)temp_files.values[i], string))
-               {
-                       clear_table_entry(&temp_files, i, 1);
-                       break;
-               }
-       }
-}
-
 
 int BC_Signals::x_error_handler(Display *display, XErrorEvent *event)
 {
@@ -519,9 +269,8 @@ int BC_Signals::x_error_handler(Display *display, XErrorEvent *event)
 void BC_Signals::initialize()
 {
        BC_Signals::global_signals = this;
-       lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
+       BC_Trace::global_trace = this;
        handler_lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
-       pthread_mutex_init(lock, 0);
        pthread_mutex_init(handler_lock, 0);
        old_err_handler = XSetErrorHandler(x_error_handler);
        initialize2();
@@ -530,6 +279,7 @@ void BC_Signals::initialize()
 void BC_Signals::terminate()
 {
        BC_Signals::global_signals = 0;
+       BC_Trace::global_trace = 0;
        uncatch_segv();  uncatch_intr();
        signal(SIGHUP, SIG_DFL);
        signal(SIGINT, SIG_DFL);
@@ -541,15 +291,6 @@ void BC_Signals::terminate()
        XSetErrorHandler(old_err_handler);
 }
 
-// callable from debugger
-extern "C"
-void dump()
-{
-       BC_Signals::dump_traces();
-       BC_Signals::dump_locks();
-       BC_Signals::dump_buffers();
-}
-
 // kill SIGUSR2
 void BC_Signals::signal_dump(int signum)
 {
@@ -589,227 +330,6 @@ const char* BC_Signals::sig_to_str(int number)
        return signal_titles[number];
 }
 
-#define TOTAL_TRACES 16
-
-void BC_Signals::new_trace(const char *text)
-{
-       if(!global_signals) return;
-       pthread_mutex_lock(lock);
-
-// Wrap around
-       if(execution_table.size >= TOTAL_TRACES)
-       {
-               overwrite_table(&execution_table, strdup(text));
-//             clear_table(&execution_table, 1);
-       }
-       else
-       {
-               append_table(&execution_table, strdup(text));
-       }
-       pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::new_trace(const char *file, const char *function, int line)
-{
-       char string[BCTEXTLEN];
-       snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
-       new_trace(string);
-}
-
-void BC_Signals::delete_traces()
-{
-       if(!global_signals) return;
-       pthread_mutex_lock(lock);
-       clear_table(&execution_table, 0);
-       pthread_mutex_unlock(lock);
-}
-
-// no canceling with lock held
-void BC_Signals::lock_locks(const char *s)
-{
-       pthread_mutex_lock(lock);
-       last_lock_thread = pthread_self();
-       last_lock_title = s;
-       last_lock_location = 0;
-}
-
-void BC_Signals::unlock_locks()
-{
-       pthread_mutex_unlock(lock);
-}
-
-#define TOTAL_LOCKS 256
-
-int BC_Signals::set_lock(void *ptr,
-       const char *title,
-       const char *location)
-{
-       if(!global_signals) return 0;
-       bc_locktrace_t *table = 0;
-       int id_return = 0;
-
-       pthread_mutex_lock(lock);
-       last_lock_thread = pthread_self();
-       last_lock_title = title;
-       last_lock_location = location;
-       if(lock_table.size >= TOTAL_LOCKS)
-               clear_table(&lock_table, 0);
-
-// Put new lock entry
-       table = new_bc_locktrace(ptr, title, location);
-       append_table(&lock_table, table);
-       id_return = table->id;
-
-       pthread_mutex_unlock(lock);
-       return id_return;
-}
-
-void BC_Signals::set_lock2(int table_id)
-{
-       if(!global_signals) return;
-
-       bc_locktrace_t *table = 0;
-       pthread_mutex_lock(lock);
-       for(int i = lock_table.size - 1; i >= 0; i--)
-       {
-               table = (bc_locktrace_t*)lock_table.values[i];
-// Got it.  Hasn't been unlocked/deleted yet.
-               if(table->id == table_id)
-               {
-                       table->is_owner = 1;
-                       table->tid = pthread_self();
-                       pthread_mutex_unlock(lock);
-                       return;
-               }
-       }
-       pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::unset_lock2(int table_id)
-{
-       if(!global_signals) return;
-
-       bc_locktrace_t *table = 0;
-       pthread_mutex_lock(lock);
-       for(int i = lock_table.size - 1; i >= 0; i--)
-       {
-               table = (bc_locktrace_t*)lock_table.values[i];
-               if(table->id == table_id)
-               {
-                       clear_table_entry(&lock_table, i, 1);
-                       break;
-               }
-       }
-       pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::unset_lock(void *ptr)
-{
-       if(!global_signals) return;
-
-       bc_locktrace_t *table = 0;
-       pthread_mutex_lock(lock);
-
-// Take off currently held entry
-       for(int i = 0; i < lock_table.size; i++)
-       {
-               table = (bc_locktrace_t*)lock_table.values[i];
-               if(table->ptr == ptr)
-               {
-                       if(table->is_owner)
-                       {
-                               clear_table_entry(&lock_table, i, 1);
-                               break;
-                       }
-               }
-       }
-
-       pthread_mutex_unlock(lock);
-}
-
-
-void BC_Signals::unset_all_locks(void *ptr)
-{
-       if(!global_signals) return;
-       pthread_mutex_lock(lock);
-// Take off previous lock entry
-       for(int i = 0; i < lock_table.size; )
-       {
-               bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
-               if(table->ptr == ptr)
-               {
-                       clear_table_entry(&lock_table, i, 1);
-                       continue;
-               }
-               ++i;
-       }
-       pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::clear_locks_tid(pthread_t tid)
-{
-       if(!global_signals) return;
-       pthread_mutex_lock(lock);
-// Take off previous lock entry
-       for(int i = 0; i < lock_table.size; )
-       {
-               bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
-               if(table->tid == tid)
-               {
-                       clear_table_entry(&lock_table, i, 1);
-                       continue;
-               }
-               ++i;
-       }
-       pthread_mutex_unlock(lock);
-}
-
-
-void BC_Signals::enable_memory()
-{
-       trace_memory = 1;
-}
-
-void BC_Signals::disable_memory()
-{
-       trace_memory = 0;
-}
-
-
-void BC_Signals::set_buffer(int size, void *ptr, const char* location)
-{
-       if(!global_signals) return;
-       if(!trace_memory) return;
-
-//printf("BC_Signals::set_buffer %p %s\n", ptr, location);
-       pthread_mutex_lock(lock);
-       append_table(&memory_table, new_bc_buffertrace(size, ptr, location));
-       pthread_mutex_unlock(lock);
-}
-
-int BC_Signals::unset_buffer(void *ptr)
-{
-       if(!global_signals) return 0;
-       if(!trace_memory) return 0;
-
-       int ret = 1;
-       pthread_mutex_lock(lock);
-       for(int i = 0; i < memory_table.size; i++)
-       {
-               if(((bc_buffertrace_t*)memory_table.values[i])->ptr == ptr)
-               {
-//printf("BC_Signals::unset_buffer %p\n", ptr);
-                       clear_table_entry(&memory_table, i, 1);
-                       ret = 0;
-                       break;
-               }
-       }
-
-       pthread_mutex_unlock(lock);
-//     fprintf(stderr, "BC_Signals::unset_buffer buffer %p not found.\n", ptr);
-       return ret;
-}
-
 
 #include <ucontext.h>
 #include <sys/wait.h>
@@ -866,10 +386,10 @@ static void handle_dump(int n, siginfo_t * info, void *sc)
        }
        fprintf(fp,"\nCPUS: %d\n",   BC_Resources::get_machine_cpus());
        fprintf(fp,"\nCPUINFO:\n");  bc_copy_textfile(32, fp,"/proc/cpuinfo");
-       fprintf(fp,"\nTHREADS:\n");  Thread::dump_threads(fp);
-       fprintf(fp,"\nTRACES:\n");   BC_Signals::dump_traces(fp);
-       fprintf(fp,"\nLOCKS:\n");    BC_Signals::dump_locks(fp);
-       fprintf(fp,"\nBUFFERS:\n");  BC_Signals::dump_buffers(fp);
+       fprintf(fp,"\nTHREADS:\n");  BC_Trace::dump_threads(fp);
+       fprintf(fp,"\nTRACES:\n");   BC_Trace::dump_traces(fp);
+       fprintf(fp,"\nLOCKS:\n");    BC_Trace::dump_locks(fp);
+       fprintf(fp,"\nBUFFERS:\n");  BC_Trace::dump_buffers(fp);
        if( BC_Signals::trap_hook ) {
                fprintf(fp,"\nMAIN HOOK:\n");
                BC_Signals::trap_hook(fp, BC_Signals::trap_data);
@@ -923,45 +443,3 @@ static void handle_dump(int n, siginfo_t * info, void *sc)
         execvp(argv[0], &argv[0]);
 }
 
-
-
-
-
-#ifdef TRACE_MEMORY
-
-// void* operator new(size_t size)
-// {
-// //printf("new 1 %d\n", size);
-//     void *result = malloc(size);
-//     BUFFER(size, result, "new");
-// //printf("new 2 %d\n", size);
-//     return result;
-// }
-//
-// void* operator new[](size_t size)
-// {
-// //printf("new [] 1 %d\n", size);
-//     void *result = malloc(size);
-//     BUFFER(size, result, "new []");
-// //printf("new [] 2 %d\n", size);
-//     return result;
-// }
-//
-// void operator delete(void *ptr)
-// {
-// //printf("delete 1 %p\n", ptr);
-//     UNBUFFER(ptr);
-// //printf("delete 2 %p\n", ptr);
-//     free(ptr);
-// }
-//
-// void operator delete[](void *ptr)
-// {
-// //printf("delete [] 1 %p\n", ptr);
-//     UNBUFFER(ptr);
-//     free(ptr);
-// //printf("delete [] 2 %p\n", ptr);
-// }
-
-
-#endif
index 05d44f8732701d18505f0e0ca66224b058fbec18..25da74f4f9e256f24baa1c7339597c136fa17329 100644 (file)
 #define BCSIGNALS_H
 
 #include "arraylist.h"
+#include "linklist.h"
 #include "bcsignals.inc"
+#include "bctrace.h"
 #include <stdio.h>
 #include <pthread.h>
 #include <signal.h>
 #include <X11/Xlib.h>
 
-#define TRON(x) BC_Signals::new_function(x);
-#define TROFF(x) BC_Signals::delete_function(x);
-
 // BC_Signals must be initialized at the start of every program using
 // debugging.
-//#define ENABLE_TRACE
-#define TRACE_LOCKS
-//#ifdef TRACE_LOCKS
-//#undef TRACE_LOCKS
-//#endif
-//#define TRACE_MEMORY
-
 
-// Need to use structs to avoid the memory manager.
-// One of these tables is created every time someone locks a lock.
-// After successfully locking, the table is flagged as being the owner of the lock.
-// In the unlock function, the table flagged as the owner of the lock is deleted.
-typedef struct 
-{
-       void *ptr;
-       const char *title;
-       const char *location;
-       int is_owner;
-       int id;
-       pthread_t tid;
-} bc_locktrace_t;
-
-class BC_Signals
+class BC_Signals : public BC_Trace
 {
        int (*old_err_handler)(Display *, XErrorEvent *);
        static int x_error_handler(Display *display, XErrorEvent *event);
@@ -69,126 +47,10 @@ public:
        void initialize2();
        void terminate();
 
-
        virtual void signal_handler(int signum);
-
        static void dump_stack(FILE *fp=stdout);
-
-#ifdef ENABLE_TRACE
-// Add a trace
-#define TRACE(text) BC_Signals::new_trace(text);
-#define SET_TRACE BC_Signals::new_trace(__FILE__, __FUNCTION__, __LINE__);
-#define PRINT_TRACE { printf("%s: %d\n", __FILE__, __LINE__); fflush(stdout); }
-// Delete all traces
-#define UNTRACE BC_Signals::delete_traces();
-
-#else
-
-#define TRACE(text) ;
-#define UNTRACE ;
-#define PRINT_TRACE { printf("%s: %d\n", __FILE__, __LINE__); fflush(stdout); }
-//#define PRINT_TRACE ;
-#define SET_TRACE ;
-
-#endif
-
-
-#ifdef TRACE_LOCKS
-
-// Before user acquires
-#define SET_LOCK(ptr, title, location) int table_id = BC_Signals::set_lock(ptr, title, location);
-// After successful acquisition of a mutex, the table is flagged
-#define SET_LOCK2 BC_Signals::set_lock2(table_id);
-// After successful acquisition of a condition, the table is removed because
-// the user never unlocks a condition after locking it.
-// Release current lock table after failing to acquire
-#define UNSET_LOCK2 BC_Signals::unset_lock2(table_id);
-
-// Release current owner of lock
-#define UNSET_LOCK(ptr) BC_Signals::unset_lock(ptr);
-
-// Delete a lock
-#define UNSET_ALL_LOCKS(ptr) BC_Signals::unset_all_locks(ptr);
-
-#define LOCK_LOCKS(s) BC_Signals::lock_locks(s);
-#define UNLOCK_LOCKS BC_Signals::unlock_locks();
-#define CLEAR_LOCKS_TID(tid) BC_Signals::clear_locks_tid(tid);
-
-#else
-
-#define SET_LOCK(ptr, title, location) ;
-#define SET_LOCK2 ;
-#define SET_LOCK2_CONDITION ;
-#define UNSET_LOCK(ptr) ;
-#define UNSET_LOCK2 ;
-#define UNSET_ALL_LOCKS(ptr) ;
-
-#define LOCK_LOCKS(s) ;
-#define UNLOCK_LOCKS ;
-#define CLEAR_LOCKS_TID(tid) ;
-#endif
-
-
-#ifdef TRACE_MEMORY
-
-#define ENABLE_BUFFER BC_Signals::enable_memory();
-#define DISABLE_BUFFER BC_Signals::disable_memory();
-// Note the size, pointer, and location of an allocation
-#define BUFFER(size, ptr, location) BC_Signals::set_buffer(size, ptr, location);
-// Note the pointer and location of an allocation
-#define BUFFER2(ptr, location) BC_Signals::set_buffer(0, ptr, location);
-// Remove a pointer from the allocation table
-#define UNBUFFER(ptr) BC_Signals::unset_buffer(ptr);
-
-#else
-
-#define ENABLE_BUFFER ;
-#define DISABLE_BUFFER ;
-#define BUFFER(size, ptr, location);
-#define UNBUFFER(ptr);
-
-#endif
-
-// Handling of temporary files in crash
-#define SET_TEMP BC_Signals::set_temp
-#define UNSET_TEMP BC_Signals::unset_temp
-
-// Forks need to reset the lock status in case they forked when a lock was held.
-       static void reset_locks();
-
-// Temporary files
-       static void delete_temps();
-       static void set_temp(char *string);
-       static void unset_temp(char *string);
        static void signal_dump(int signum);
-
-
        static void kill_subs();
-
-       static int set_lock(void *ptr, const char *title, const char *location);
-       static void set_lock2(int table_id);
-       static void set_lock2_condition(int table_id);
-       static void unset_lock2(int table_id);
-       static void unset_lock(void *ptr);
-// Used in lock destructors so takes away all references
-       static void unset_all_locks(void *ptr);
-       static void clear_locks_tid(pthread_t tid);
-
-       static void new_trace(const char *text);
-       static void new_trace(const char *file, const char *function, int line);
-       static void delete_traces();
-
-       static void enable_memory();
-       static void disable_memory();
-       static void set_buffer(int size, void *ptr, const char* location);
-// This one returns 1 if the buffer wasn't found.
-       static int unset_buffer(void *ptr);
-       static void lock_locks(const char *s);
-       static void unlock_locks();
-
-       static void dump_traces(FILE *fp=stdout);
-       static void dump_locks(FILE *fp=stdout);
-       static void dump_buffers(FILE *fp=stdout);
        static void set_sighup_exit(int enable);
 
        static void set_trap_path(const char *path);
@@ -206,5 +68,4 @@ public:
        static bool trap_sigsegv, trap_sigintr;
 };
 
-
 #endif
diff --git a/cinelerra-5.1/guicast/bctrace.C b/cinelerra-5.1/guicast/bctrace.C
new file mode 100644 (file)
index 0000000..ee1c6fa
--- /dev/null
@@ -0,0 +1,401 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "bctrace.h"
+
+BC_Trace *BC_Trace::global_trace = 0;
+int trace_memory = 0;
+int trace_locks = 1;
+
+BC_Trace::BC_Trace()
+{
+}
+BC_Trace::~BC_Trace()
+{
+}
+
+bc_trace_mutex execution_table;
+bc_trace_mutex memory_table;
+bc_trace_mutex lock_table;
+bc_trace_list lock_free;
+bc_trace_mutex file_table;
+
+// incase lock set after task ends
+static pthread_t last_lock_thread = 0;
+static const char *last_lock_title = 0;
+static const char *last_lock_location = 0;
+
+trace_item::trace_item(bc_trace_t &t) : table(t) { ++table.size; }
+trace_item::~trace_item() { --table.size; } 
+
+extern "C" void dump()
+{
+       BC_Trace::dump_traces();
+       BC_Trace::dump_locks();
+       BC_Trace::dump_buffers();
+}
+
+#define TOTAL_TRACES 16
+
+void BC_Trace::new_trace(const char *text)
+{
+       if(!global_trace) return;
+       execution_table.lock();
+       execution_item *it;
+       if( execution_table.size >= TOTAL_TRACES ) {
+               it = (execution_item *)execution_table.first;
+               execution_table.remove_pointer(it);
+       }
+       else
+               it = new execution_item();
+       it->set(text);
+       execution_table.append(it);
+       execution_table.unlock();
+}
+
+void BC_Trace::new_trace(const char *file, const char *function, int line)
+{
+       char string[BCTEXTLEN];
+       snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
+       new_trace(string);
+}
+
+void BC_Trace::delete_traces()
+{
+       if(!global_trace) return;
+       execution_table.lock();
+       execution_table.clear();
+       execution_table.unlock();
+}
+
+void BC_Trace::enable_locks()
+{
+       lock_table.lock();
+       trace_locks = 1;
+       lock_table.unlock();
+}
+
+void BC_Trace::disable_locks()
+{
+       lock_table.lock();
+       trace_locks = 0;
+       while( lock_table.last ) {
+               lock_item *p = (lock_item*)lock_table.last;
+               p->info->trace = 0;
+               lock_table.remove_pointer(p);  lock_free.append(p);
+       }
+       lock_free.clear();
+       lock_table.unlock();
+}
+
+// no canceling with lock held
+void BC_Trace::lock_locks(const char *s)
+{
+       lock_table.lock();
+       last_lock_thread = pthread_self();
+       last_lock_title = s;
+       last_lock_location = 0;
+}
+
+void BC_Trace::unlock_locks()
+{
+       lock_table.unlock();
+}
+
+#define TOTAL_LOCKS 256
+
+int BC_Trace::set_lock(const char *title, const char *loc, trace_info *info)
+{
+       if( !global_trace || !trace_locks ) return 0;
+       lock_table.lock();
+       last_lock_thread = pthread_self();
+       last_lock_title = title;
+       last_lock_location = loc;
+       lock_item *it;
+       if( lock_table.size >= TOTAL_LOCKS ) {
+               it = (lock_item*)lock_table.first;
+               lock_table.remove_pointer(it);
+       }
+       else if( (it=(lock_item*)lock_free.first) != 0 )
+               lock_free.remove_pointer(it);
+       else
+               it = new lock_item();
+       it->set(info, title, loc);
+       lock_table.append(it);
+       info->trace = (void *)it;
+       lock_table.unlock();
+       return it->id;
+}
+
+void BC_Trace::set_lock2(int table_id, trace_info *info)
+{
+       if( !global_trace || !trace_locks ) return;
+       lock_table.lock();
+       lock_item *p = (lock_item *)info->trace;
+       if( !p || p->id != table_id ) {
+               p = (lock_item*)lock_table.last;
+               while( p && p->id != table_id ) p = (lock_item*)p->previous;
+       }
+       if( p ) {
+               info->trace = (void *)p;
+               p->is_owner = 1;
+               p->tid = pthread_self();
+       }
+       lock_table.unlock();
+}
+
+void BC_Trace::unset_lock2(int table_id, trace_info *info)
+{
+       if( !global_trace || !trace_locks ) return;
+       lock_table.lock();
+       lock_item *p = (lock_item *)info->trace;
+       if( !p || p->id != table_id ) {
+               p = (lock_item*)lock_table.last;
+               while( p && p->id != table_id ) p = (lock_item*)p->previous;
+       }
+       else
+               info->trace = 0;
+       if( p ) { lock_table.remove_pointer(p);  lock_free.append(p); }
+       lock_table.unlock();
+}
+
+void BC_Trace::unset_lock(trace_info *info)
+{
+       if( !global_trace || !trace_locks ) return;
+       lock_table.lock();
+       lock_item *p = (lock_item *)info->trace;
+       if( !p || p->info!=info || !p->is_owner ) {
+               p = (lock_item*)lock_table.last;
+               while( p && ( p->info!=info || !p->is_owner ) ) p = (lock_item*)p->previous;
+       }
+       else
+               info->trace = 0;
+       if( p ) { lock_table.remove_pointer(p);  lock_free.append(p); }
+       lock_table.unlock();
+}
+
+
+void BC_Trace::unset_all_locks(trace_info *info)
+{
+       if( !global_trace || !trace_locks ) return;
+       lock_table.lock();
+       lock_item *p = (lock_item*)lock_table.first;
+       while( p ) {
+               lock_item *lp = p;  p = (lock_item*)p->next;
+               if( lp->info != info ) continue;
+               lock_table.remove_pointer(p);  lock_free.append(p);
+       }
+       lock_table.unlock();
+}
+
+void BC_Trace::clear_locks_tid(pthread_t tid)
+{
+       if( !global_trace || !trace_locks ) return;
+       lock_table.lock();
+       lock_item *p = (lock_item*)lock_table.first;
+       while( p ) {
+               lock_item *lp = p;  p = (lock_item*)p->next;
+               if( lp->tid != tid ) continue;
+               lock_table.remove_pointer(p);  lock_free.append(p);
+       }
+       lock_table.unlock();
+}
+
+
+void BC_Trace::enable_memory()
+{
+       trace_memory = 1;
+}
+
+void BC_Trace::disable_memory()
+{
+       trace_memory = 0;
+}
+
+
+void BC_Trace::set_buffer(int size, void *ptr, const char* loc)
+{
+       if(!global_trace) return;
+       if(!trace_memory) return;
+       memory_table.lock();
+//printf("BC_Trace::set_buffer %p %s\n", ptr, loc);
+       memory_table.append(new memory_item(size, ptr, loc));
+       memory_table.unlock();
+}
+
+int BC_Trace::unset_buffer(void *ptr)
+{
+       if(!global_trace) return 0;
+       if(!trace_memory) return 0;
+       memory_table.lock();
+       memory_item *p = (memory_item*)memory_table.first;
+       for( ; p!=0 && p->ptr!=ptr; p=(memory_item*)p->next );
+       if( p ) delete p;
+       memory_table.unlock();
+       return !p ? 1 : 0;
+}
+
+#ifdef TRACE_MEMORY
+
+void* operator new(size_t size)
+{
+       void *result = malloc(size);
+       BUFFER(size, result, "new");
+       return result;
+}
+
+void* operator new[](size_t size)
+{
+       void *result = malloc(size);
+       BUFFER(size, result, "new []");
+       return result;
+}
+
+void operator delete(void *ptr)
+{
+       UNBUFFER(ptr);
+       free(ptr);
+}
+
+void operator delete[](void *ptr)
+{
+       UNBUFFER(ptr);
+       free(ptr);
+}
+
+#endif
+
+void BC_Trace::dump_traces(FILE *fp)
+{
+// Dump trace table
+       for( trace_item *tp=execution_table.first; tp!=0; tp=tp->next ) {
+               execution_item *p=(execution_item*)tp;
+               fprintf(fp,"    %s\n", (char*)p->value);
+       }
+}
+
+void BC_Trace::dump_locks(FILE *fp)
+{
+// Dump lock table
+#ifdef TRACE_LOCKS
+       fprintf(fp,"signal_entry: lock table size=%d\n", lock_table.size);
+       for( trace_item *tp=lock_table.first; tp!=0; tp=tp->next ) {
+               lock_item *p=(lock_item*)tp;
+               fprintf(fp,"    %p %s %s %p%s\n", p->info, p->title,
+                       p->loc, (void*)p->tid, p->is_owner ? " *" : "");
+       }
+#endif
+}
+
+void BC_Trace::dump_buffers(FILE *fp)
+{
+#ifdef TRACE_MEMORY
+       memory_table.lock();
+// Dump buffer table
+       fprintf(fp,"BC_Trace::dump_buffers: buffer table size=%d\n", memory_table.size);
+       for( trace_item *tp=memory_table.first; tp!=0; tp=tp->next ) {
+               memory_item *p=(memory_item*)tp;
+               fprintf(fp,"    %d %p %s\n", p->size, p->ptr, p->loc);
+       }
+       memory_table.unlock();
+#endif
+}
+
+void BC_Trace::delete_temps()
+{
+       file_table.lock();
+       if( file_table.size )
+               printf("BC_Trace::delete_temps: deleting %d temp files\n", file_table.size);
+       while( file_table.first ) {
+               file_item *p = (file_item*)file_table.first;
+               printf("    %s\n", p->value);
+               ::remove(p->value);
+               delete p;
+       }
+       file_table.unlock();
+}
+
+void BC_Trace::reset_locks()
+{
+       lock_table.unlock();
+}
+
+void BC_Trace::set_temp(char *string)
+{
+       file_table.lock();
+       file_item *it = new file_item();
+       it->set(string);
+       file_table.append(it);
+       file_table.unlock();
+}
+
+void BC_Trace::unset_temp(char *string)
+{
+       file_table.lock();
+       file_item *p = (file_item *)file_table.last;
+       for( ; p!=0 && strcmp(p->value,string); p=(file_item*)p->previous );
+       if( p ) delete p;
+       file_table.unlock();
+}
+
+
+#ifdef TRACE_THREADS
+
+TheLock TheLocker::the_lock;
+TheList TheList::the_list;
+TheChk TheChk::the_chk;
+
+int lock_item::table_id = 0;
+
+void TheList::dbg_add(pthread_t tid, pthread_t owner, const char *nm)
+{
+       TheLocker the_locker;
+       int i = the_list.size();
+       while( --i >= 0 && the_list[i]->tid != tid );
+       if( i >= 0 ) {
+               printf("dbg_add, dup %016lx %s %s\n",
+                       (unsigned long)tid, nm, the_list[i]->name);
+               return;
+       }
+       the_list.append(new TheDbg(tid, owner, nm));
+}
+
+void TheList::dbg_del(pthread_t tid)
+{
+       TheLocker the_locker;
+       int i = the_list.size();
+       while( --i >= 0 && the_list[i]->tid != tid );
+       if( i < 0 ) {
+               printf("dbg_del, mis %016lx\n",(unsigned long)tid);
+               return;
+       }
+       the_list.remove_object_number(i);
+}
+
+
+void TheList::dump_threads(FILE *fp)
+{
+       int i = the_list.size();
+       while( --i >= 0 ) {
+               fprintf(fp, "thread 0x%012lx, owner 0x%012lx, %s\n",
+                       (unsigned long)the_list[i]->tid, (unsigned long)the_list[i]->owner,
+                       the_list[i]->name);
+       }
+}
+
+#else
+#define dbg_add(t, o, nm) do {} while(0)
+#define dbg_del(t) do {} while(0)
+void TheList::dump_threads(FILE *fp)
+{
+}
+#endif
+
+void BC_Trace::dump_threads(FILE *fp)
+{
+       TheList::dump_threads(fp);
+}
+
+
diff --git a/cinelerra-5.1/guicast/bctrace.h b/cinelerra-5.1/guicast/bctrace.h
new file mode 100644 (file)
index 0000000..5cbf0f5
--- /dev/null
@@ -0,0 +1,240 @@
+#ifndef __BC_TRACE_H__
+#define __BC_TRACE_H__
+
+#include "arraylist.h"
+#include "linklist.h"
+#include "bctrace.inc"
+#include "bcwindowbase.inc"
+#include "cstrdup.h"
+#include <pthread.h>
+
+
+class BC_Trace
+{
+public:
+       BC_Trace();
+       ~BC_Trace();
+
+       static BC_Trace *global_trace;
+        static void reset_locks();
+
+        static void delete_temps();
+        static void set_temp(char *string);
+        static void unset_temp(char *string);
+
+       static void enable_locks();
+       static void disable_locks();
+       static int set_lock(const char *title, const char *location, trace_info *info);
+       static void set_lock2(int table_id, trace_info *info);
+       static void unset_lock2(int table_id, trace_info *info);
+       static void unset_lock(trace_info *info);
+// Used in lock destructors so takes away all references
+       static void unset_all_locks(trace_info *info);
+       static void clear_locks_tid(pthread_t tid);
+
+       static void new_trace(const char *text);
+       static void new_trace(const char *file, const char *function, int line);
+       static void delete_traces();
+
+       static void enable_memory();
+       static void disable_memory();
+       static void set_buffer(int size, void *ptr, const char* location);
+// This one returns 1 if the buffer wasn't found.
+       static int unset_buffer(void *ptr);
+       static void lock_locks(const char *s);
+       static void unlock_locks();
+
+       static void dump_traces(FILE *fp=stdout);
+       static void dump_locks(FILE *fp=stdout);
+       static void dump_buffers(FILE *fp=stdout);
+       static void dump_threads(FILE *fp=stdout);
+};
+
+class bc_trace_list : public List<trace_item> {
+public:
+       void clear() { while( last ) remove(last); }
+       bc_trace_list() {}
+       ~bc_trace_list() { clear(); }
+};
+
+class bc_trace_t : public bc_trace_list {
+public:
+       int size;
+       bc_trace_t() : size(0) {}
+       ~bc_trace_t() {}
+};
+
+class bc_trace_spin : public bc_trace_t {
+       pthread_spinlock_t spin;
+public:
+       void *operator new(size_t n) { return (void*) malloc(n); }
+       void operator delete(void *t, size_t n) { free(t); }
+
+       void lock() { pthread_spin_lock(&spin); }
+       void unlock() { pthread_spin_unlock(&spin); }
+       bc_trace_spin() { pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE); }
+       ~bc_trace_spin() { pthread_spin_destroy(&spin); }
+};
+
+class bc_trace_mutex : public bc_trace_t {
+       pthread_mutex_t mutex;
+public:
+       void *operator new(size_t n) { return (void*) malloc(n); }
+       void operator delete(void *t, size_t n) { free(t); }
+
+       void lock() { pthread_mutex_lock(&mutex); }
+       void unlock() { pthread_mutex_unlock(&mutex); }
+       bc_trace_mutex() { pthread_mutex_init(&mutex, 0); }
+       ~bc_trace_mutex() { pthread_mutex_destroy(&mutex); }
+};
+
+extern bc_trace_mutex execution_table;
+extern bc_trace_mutex memory_table;
+extern bc_trace_mutex lock_table;
+extern bc_trace_mutex file_table;
+extern "C" void dump();
+
+class trace_item : public ListItem<trace_item> {
+public:
+       bc_trace_t &table;
+       trace_item(bc_trace_t &t);
+       ~trace_item();
+};
+
+class execution_item : public trace_item {
+public:
+       void *operator new(size_t n) { return (void*) malloc(n); }
+       void operator delete(void *t, size_t n) { free(t); }
+
+       const char *value;
+       void clear() { delete [] value;  value = 0; }
+       void set(const char *v) { delete [] value;  value = cstrdup(v); }
+
+       execution_item() : trace_item(execution_table) { value = 0; }
+       ~execution_item() { clear(); }
+};
+
+class lock_item : public trace_item {
+       static int table_id;
+public:
+       void *operator new(size_t n) { return (void*) malloc(n); }
+       void operator delete(void *t, size_t n) { free(t); }
+
+        trace_info *info;
+        const char *title;
+        const char *loc;
+        int is_owner;
+        int id;
+        pthread_t tid;
+       void set(trace_info *info, const char *title, const char *loc) {
+               this->info = info;  this->title = title;
+               this->loc = loc;  this->is_owner = 0;
+               this->id = table_id++;  this->tid = pthread_self();
+       }
+       void clear() { 
+               this->info = 0;  this->title = 0; this->loc = 0;
+               this->is_owner = 0;  this->id = -1;  this->tid = 0;
+       }
+
+       lock_item() : trace_item(lock_table) { clear(); }
+       ~lock_item() {}
+};
+
+class memory_item : public trace_item {
+public:
+       void *operator new(size_t n) { return (void*) malloc(n); }
+       void operator delete(void *t, size_t n) { free(t); }
+
+       int size;
+       void *ptr;
+       const char *loc;
+
+       memory_item(int size, void *ptr, const char *loc)
+        : trace_item(memory_table) {
+               this->size = size; this->ptr = ptr; this->loc = loc;
+       }
+       ~memory_item() {}
+};
+
+class file_item : public trace_item {
+public:
+       void *operator new(size_t n) { return (void*) malloc(n); }
+       void operator delete(void *t, size_t n) { free(t); }
+
+       const char *value;
+       void clear() { delete [] value;  value = 0; }
+       void set(const char *v) { delete [] value;  value = cstrdup(v); }
+
+       file_item() : trace_item(file_table) { value = 0; }
+       ~file_item() { clear(); }
+};
+
+// track unjoined threads at termination
+#ifdef TRACE_THREADS
+
+class TheLock {
+public:
+       pthread_mutex_t the_lock;
+
+       void lock() { pthread_mutex_lock(&the_lock); }
+       void unlock() { pthread_mutex_unlock(&the_lock); }
+
+       TheLock() {
+               pthread_mutexattr_t attr;
+               pthread_mutexattr_init(&attr);
+               pthread_mutex_init(&the_lock, &attr);
+       }
+       ~TheLock() {
+               pthread_mutex_destroy(&the_lock);
+       }
+};
+
+class TheLocker {
+public:
+       static TheLock the_lock;
+
+       TheLocker() { the_lock.lock(); }
+       ~TheLocker() { the_lock.unlock(); }
+};
+
+class TheDbg {
+public:
+       pthread_t tid, owner;  const char *name;
+       TheDbg(pthread_t t, pthread_t o, const char *nm) { tid = t; owner = o; name = nm; }
+       ~TheDbg() {}
+};
+
+
+class TheList : public ArrayList<TheDbg *> {
+public:
+       static TheList the_list;
+       static void dump_threads(FILE *fp);
+       static void dbg_add(pthread_t tid, pthread_t owner, const char *nm);
+       static void dbg_del(pthread_t tid);
+
+        TheList() {}
+       ~TheList() {
+               TheLocker the_locker;
+               remove_all_objects();
+       }
+};
+
+class TheChk {
+public:
+       static TheChk the_chk;
+
+       TheChk() {}
+       ~TheChk() {
+               int i = TheList::the_list.size();
+               if( !i ) return;
+               printf("unjoined tids / owner %d\n", i);
+               while( --i >= 0 ) printf("  %016lx / %016lx %s\n",
+                       (unsigned long)TheList::the_list[i]->tid,
+                       (unsigned long)TheList::the_list[i]->owner,
+                       TheList::the_list[i]->name);
+       }
+};
+
+#endif
+
+#endif
diff --git a/cinelerra-5.1/guicast/bctrace.inc b/cinelerra-5.1/guicast/bctrace.inc
new file mode 100644 (file)
index 0000000..967aa25
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef __BCTRACE_INC__
+#define __BCTRACE_INC__
+
+//#define ENABLE_TRACE
+#define TRACE_LOCKS
+//#define TRACE_MEMORY
+#define TRACE_THREADS
+#define TRACE_LOCKS
+
+class BC_Trace;
+class trace_item;
+class execution_item;
+class lock_item;
+class memory_item;
+class file_item;
+class bc_trace_t;
+class bc_trace_spin;
+class bc_trace_mutex;
+
+class TheLock;
+class TheLocker;
+class TheDbg;
+class TheList;
+class TheChk;
+
+class trace_info {
+public:
+       void *trace;
+       trace_info() { trace = 0; }
+       ~trace_info() {}
+};
+
+#ifdef NO_GUICAST
+
+#undef ENABLE_TRACE
+#undef TRACE_LOCKS
+#undef TRACE_MEMORY
+#undef TRACE_THREADS
+
+#endif
+
+
+#ifdef ENABLE_TRACE
+// Add a trace
+#define TRACE(text) BC_Trace::new_trace(text);
+#define SET_TRACE BC_Trace::new_trace(__FILE__, __FUNCTION__, __LINE__);
+#define PRINT_TRACE { printf("%s: %d\n", __FILE__, __LINE__); fflush(stdout); }
+// Delete all traces
+#define UNTRACE BC_Trace::delete_traces();
+
+#else
+
+#define TRACE(text) ;
+#define UNTRACE ;
+#define PRINT_TRACE { printf("%s: %d\n", __FILE__, __LINE__); fflush(stdout); }
+//#define PRINT_TRACE ;
+#define SET_TRACE ;
+
+#endif
+
+
+#ifdef TRACE_LOCKS
+// Before user acquires
+#define SET_LOCK(info, title, location) \
+ int table_id = BC_Trace::set_lock(title, location, info);
+// After successful acquisition of a mutex, the table is flagged
+#define SET_LOCK2 BC_Trace::set_lock2(table_id, this);
+// After successful acquisition of a condition, the table is removed because
+// the user never unlocks a condition after locking it.
+// Release current lock table after failing to acquire
+#define UNSET_LOCK2 BC_Trace::unset_lock2(table_id, this);
+
+// Release current owner of lock
+#define UNSET_LOCK(info) BC_Trace::unset_lock(info);
+// Delete a lock
+#define UNSET_ALL_LOCKS(info) BC_Trace::unset_all_locks(info);
+
+#define LOCK_LOCKS(s) BC_Trace::lock_locks(s);
+#define UNLOCK_LOCKS BC_Trace::unlock_locks();
+#define CLEAR_LOCKS_TID(tid) BC_Trace::clear_locks_tid(tid);
+
+#else
+
+#define SET_LOCK(title, location) ;
+#define SET_LOCK2 ;
+#define SET_LOCK2_CONDITION ;
+#define UNSET_LOCK(info) ;
+#define UNSET_LOCK2 ;
+#define UNSET_ALL_LOCKS(info) ;
+
+#define LOCK_LOCKS(s) ;
+#define UNLOCK_LOCKS ;
+#define CLEAR_LOCKS_TID(tid) ;
+#endif
+
+
+#ifdef TRACE_MEMORY
+
+#define ENABLE_BUFFER BC_Trace::enable_memory();
+#define DISABLE_BUFFER BC_Trace::disable_memory();
+// Note the size, pointer, and location of an allocation
+#define BUFFER(size, ptr, location) BC_Trace::set_buffer(size, ptr, location);
+// Note the pointer and location of an allocation
+#define BUFFER2(ptr, location) BC_Trace::set_buffer(0, ptr, location);
+// Remove a pointer from the allocation table
+#define UNBUFFER(ptr) BC_Trace::unset_buffer(ptr);
+
+#else
+
+#define ENABLE_BUFFER ;
+#define DISABLE_BUFFER ;
+#define BUFFER(size, ptr, location);
+#define UNBUFFER(ptr);
+
+#endif
+
+// Handling of temporary files in crash
+#define SET_TEMP BC_Trace::set_temp
+#define UNSET_TEMP BC_Trace::unset_temp
+
+#endif
index 65b68a6fca40db014a81662d15c918a1ca4555ba..7dd78161597ce4fb947adb042fc6f26e4283c8c9 100644 (file)
@@ -142,7 +142,8 @@ int BC_Tumbler::repeat_event(int64_t duration)
        {
 //printf("BC_Tumbler::repeat_event 2\n");
                repeat_count++;
-               if(repeat_count == 2) return 0;
+// delay the 1st repeat
+               if(repeat_count > 1 && repeat_count < 5) return 0;
                if(status == TUMBLETOP_DN)
                {
                        handle_up_event();
index b6d54fe0e9fc822526bfa64447f975678c86facd..b4e4268520d2d8bc2476820dfb241e39d4cbc7aa 100644 (file)
@@ -250,6 +250,7 @@ int BC_WindowBase::initialize()
        done = 0;
        done_set = 0;
        window_running = 0;
+       display_lock_owner = 0;
        test_keypress = 0;
        keys_return[0] = 0;
        is_deleting = 0;
index aeaba388e952235288b83c02730fe6c286874093..c2ed7abc270bd98f01d17fbf51a62f441e264eca 100644 (file)
@@ -65,6 +65,7 @@
 #include "bctimer.inc"
 #include "bctitle.inc"
 #include "bctoggle.inc"
+#include "bctrace.inc"
 #include "bctumble.inc"
 #include "bcwindow.inc"
 #include "bcwindowbase.inc"
@@ -124,7 +125,7 @@ public:
 
 
 // Windows, subwindows, popupwindows inherit from this
-class BC_WindowBase
+class BC_WindowBase : public trace_info
 {
 public:
        BC_WindowBase(int opts=0);
index d9b64fa1694c6d9fc3e6e98935d547705e7fa1f1..8a7d5c3b72284b9963fdeae59d76fae1d10cd5de 100644 (file)
@@ -40,6 +40,7 @@
 #undef DISTANCE
 #define DISTANCE(x1, y1, x2, y2) \
 (sqrt(((x2) - (x1)) * ((x2) - (x1)) + ((y2) - (y1)) * ((y2) - (y1))))
-
+#define TO_RAD(x) ((x) * 2 * M_PI / 360)
+#define TO_DEG(x) ((x) * 360 / 2 / M_PI)
 
 #endif
index f45a9cd8785decfbe77f91f8a4776e0231333ba4..15bc0239ec3a77c93524ac414b0745d529067519 100644 (file)
@@ -19,9 +19,7 @@
  * 
  */
 
-#ifndef NO_GUICAST
 #include "bcsignals.h"
-#endif
 #include "condition.h"
 
 #include <errno.h>
@@ -34,6 +32,7 @@ Condition::Condition(int init_value, const char *title, int is_binary)
 {
        this->is_binary = is_binary;
        this->title = title;
+       this->trace = 0;
        pthread_mutex_init(&mutex, 0);
        pthread_cond_init(&cond, NULL);
        this->value = this->init_value = init_value;
@@ -43,9 +42,7 @@ Condition:: ~Condition()
 {
        pthread_cond_destroy(&cond);
        pthread_mutex_destroy(&mutex);
-#ifndef NO_GUICAST
        UNSET_ALL_LOCKS(this);
-#endif
 }
 
 void Condition::reset()
@@ -54,19 +51,17 @@ void Condition::reset()
        pthread_mutex_destroy(&mutex);
        pthread_mutex_init(&mutex, 0);
        pthread_cond_init(&cond, NULL);
+       UNSET_ALL_LOCKS(this);
        value = init_value;
+       trace = 0;
 }
 
 void Condition::lock(const char *location)
 {
-#ifndef NO_GUICAST
        SET_LOCK(this, title, location);
-#endif
        pthread_mutex_lock(&mutex);
        while(value <= 0) pthread_cond_wait(&cond, &mutex);
-#ifndef NO_GUICAST
        UNSET_LOCK2
-#endif
        if(is_binary)
                value = 0;
        else
@@ -77,9 +72,7 @@ void Condition::lock(const char *location)
 void Condition::unlock()
 {
 // The lock trace is created and removed by the acquirer
-//#ifndef NO_GUICAST
 //     UNSET_LOCK(this);
-//#endif
        pthread_mutex_lock(&mutex);
        if(is_binary)
                value = 1;
@@ -93,9 +86,7 @@ int Condition::timed_lock(int microseconds, const char *location)
 {
        int result = 0;
 
-#ifndef NO_GUICAST
        SET_LOCK(this, title, location);
-#endif
        pthread_mutex_lock(&mutex);
 
        struct timeval now;
@@ -131,9 +122,7 @@ int Condition::timed_lock(int microseconds, const char *location)
        }
 #endif
 
-#ifndef NO_GUICAST
        UNSET_LOCK2
-#endif
 //printf("Condition::timed_lock 2 %d %s %s\n", result, title, location);
        if( !result ) {
                if(is_binary)
index 1fd455e2e1400d42c452670e1ed2df1b45a13333..bae5acfc2b2a25c7132f985307b3fb37da43891b 100644 (file)
@@ -23,8 +23,9 @@
 #define CONDITION_H
 
 #include <pthread.h>
+#include "bctrace.inc"
 
-class Condition
+class Condition : public trace_info
 {
 public:
        Condition(int init_value = 0, const char *title = 0, int is_binary = 0);
index 6bbf279e78396f033460a1a8cfd20a3f150e3561..c6cddd7639827ea6ddb89df9629d02a16a58dc04 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 
-#ifndef NO_GUICAST
 #include "bcsignals.h"
-#endif
 #include "mutex.h"
 
 
 Mutex::Mutex(const char *title, int recursive)
 {
        this->title = title;
+       this->trace = 0;
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutex_init(&mutex, &attr);
@@ -45,9 +44,7 @@ Mutex::~Mutex()
 {
        pthread_mutex_destroy(&mutex);
        pthread_mutex_destroy(&recursive_lock);
-#ifndef NO_GUICAST
        UNSET_ALL_LOCKS(this);
-#endif
 }
 
 int Mutex::lock(const char *location)
@@ -66,9 +63,7 @@ int Mutex::lock(const char *location)
        }
 
 
-#ifndef NO_GUICAST
        SET_LOCK(this, title, location);
-#endif
        if(pthread_mutex_lock(&mutex)) perror("Mutex::lock");
 
 
@@ -88,9 +83,7 @@ int Mutex::lock(const char *location)
        }
 
 
-#ifndef NO_GUICAST
        SET_LOCK2
-#endif
        return 0;
 }
 
@@ -120,9 +113,7 @@ int Mutex::unlock()
                count = 0;
 
 
-#ifndef NO_GUICAST
        UNSET_LOCK(this);
-#endif
 
        if(pthread_mutex_unlock(&mutex)) perror("Mutex::unlock");
        return 0;
@@ -145,10 +136,8 @@ int Mutex::trylock(const char *location)
        else
                count = 1;
 
-#ifndef NO_GUICAST
        SET_LOCK(this, title, location);
        SET_LOCK2
-#endif
        return 0;
 }
 
@@ -163,11 +152,10 @@ int Mutex::reset()
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutex_init(&mutex, &attr);
+       UNSET_ALL_LOCKS(this)
+       trace = 0;
        count = 0;
        thread_id = 0;
        thread_id_valid = 0;
-#ifndef NO_GUICAST
-       UNSET_ALL_LOCKS(this)
-#endif
        return 0;
 }
index f510f0ddc9ef43eb445db5596c44a2d8798a7fc3..76a93584fcba16703a3d945c9ffe6f5bb0d45019 100644 (file)
@@ -24,8 +24,9 @@
 
 #include <pthread.h>
 #include <stdio.h>
+#include "bctrace.inc"
 
-class Mutex
+class Mutex : public trace_info
 {
 public:
        Mutex(const char *title = 0, int recursive = 0);
@@ -61,5 +62,4 @@ public:
        ~mLock() { mutex.unlock(); }
 };
 
-
 #endif
index 4bd1de7cbe9eca539e9bf4ecb54e1e925d46abcb..aac4455dcd5499e09dfb5ffbc0191d3afd672c90 100644 (file)
@@ -2,21 +2,21 @@
 /*
  * CINELERRA
  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
+ *
  */
 
 #include "bcsignals.h"
@@ -116,11 +116,11 @@ Sema::~Sema()
        }
 }
 
-       
+
 int Sema::lock(int number)
 {
        struct sembuf sop;
-       
+
 // decrease the semaphore
        sop.sem_num = number;
        sop.sem_op = -1;
@@ -132,7 +132,7 @@ int Sema::lock(int number)
 int Sema::unlock(int number)
 {
        struct sembuf sop;
-       
+
 // decrease the semaphore
        sop.sem_num = number;
        sop.sem_op = 1;
index 2d85f293ac4aeb430c744b4b5fadca263a03fbee..ef1eb9b02177aa73732e3824987ebf52e897b398 100644 (file)
@@ -24,8 +24,9 @@
 
 
 #include <semaphore.h>
+#include "bctrace.inc"
 
-class Sema
+class Sema : public trace_info
 {
 public:
        Sema(int init_value = 1, const char *title = 0);
@@ -43,11 +44,6 @@ public:
 
 
 
-
-
-
-
-
 #if 0
 
 
@@ -82,8 +78,4 @@ public:
 
 #endif
 
-
-
-
-
 #endif
index 355d23d551561cb0dd236fa7b508597cad1556b3..2a8c33814a99f0cdbd4ae4a7438009a2641b964c 100644 (file)
  * 
  */
 
-#ifndef NO_GUICAST
 #include "bcsignals.h"
-#endif
 #include <sys/wait.h>
 #include <sched.h>
 #include <signal.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
-#include "thread.h"
-
-// track unjoined threads at termination
-#ifndef NO_GUICAST
-#include "arraylist.h"
-#include "mutex.h"
 #include <typeinfo>
+#include "thread.h"
 
-class MLocker {
-       static Mutex the_lock;
-public:
-       MLocker() { the_lock.lock(); }
-       ~MLocker() { the_lock.unlock(); }
-};
-Mutex MLocker::the_lock;
-
-class the_dbg {
-public:
-       pthread_t tid, owner;  const char *name;
-       the_dbg(pthread_t t, pthread_t o, const char *nm) { tid = t; owner = o; name = nm; }
-       ~the_dbg() {}
-};
-
-
-static class the_list : public ArrayList<the_dbg*> {
-public:
-       static void dump_threads(FILE *fp);
-        the_list() {}
-       ~the_list() {
-               MLocker mlkr;
-               remove_all_objects();
-       }
-} thread_list;
-
-static void dbg_add(pthread_t tid, pthread_t owner, const char *nm)
-{
-       MLocker mlkr;
-       int i = thread_list.size();
-       while( --i >= 0 && thread_list[i]->tid != tid );
-       if( i >= 0 ) {
-               printf("dbg_add, dup %016lx %s %s\n",
-                       (unsigned long)tid, nm, thread_list[i]->name);
-               return;
-       }
-       thread_list.append(new the_dbg(tid, owner, nm));
-}
-
-static void dbg_del(pthread_t tid)
-{
-       MLocker mlkr;
-       int i = thread_list.size();
-       while( --i >= 0 && thread_list[i]->tid != tid );
-       if( i < 0 ) {
-               printf("dbg_del, mis %016lx\n",(unsigned long)tid);
-               return;
-       }
-       thread_list.remove_object_number(i);
-}
-
-static class the_chkr {
-public:
-       the_chkr() {}
-       ~the_chkr() {
-               int i = thread_list.size();
-               if( !i ) return;
-               printf("unjoined tids / owner %d\n", i);
-               while( --i >= 0 ) printf("  %016lx / %016lx %s\n",
-                       (unsigned long)thread_list[i]->tid,
-                       (unsigned long)thread_list[i]->owner,
-                       thread_list[i]->name);
-       }
-} the_chk;
-#else
-#define dbg_add(t, nm) do {} while(0)
-#define dbg_del(t) do {} while(0)
-#endif
 
 Thread::Thread(int synchronous, int realtime, int autodelete)
 {
@@ -140,7 +65,7 @@ void* Thread::entrypoint(void *parameters)
        thread->run();
        thread->finished = true;
        if( !thread->synchronous ) {
-               if( !thread->cancelled ) dbg_del(thread->tid);
+               if( !thread->cancelled ) TheList::dbg_del(thread->tid);
                if( thread->autodelete ) delete thread;
                else thread->tid = ((pthread_t)-1);
        }
@@ -183,7 +108,7 @@ void Thread::start()
 
        pthread_create(&tid, &attr, Thread::entrypoint, this);
 
-       dbg_add(tid, owner, typeid(*this).name());
+       TheList::dbg_add(tid, owner, typeid(*this).name());
 }
 
 int Thread::cancel()
@@ -192,7 +117,7 @@ int Thread::cancel()
                LOCK_LOCKS("Thread::cancel");
                pthread_cancel(tid);
                cancelled = true;
-               if( !synchronous ) dbg_del(tid);
+               if( !synchronous ) TheList::dbg_del(tid);
                UNLOCK_LOCKS;
        }
        return 0;
@@ -206,7 +131,7 @@ int Thread::join()   // join this thread
                int ret = pthread_join(tid, 0);
                if( ret ) strerror(ret);
                CLEAR_LOCKS_TID(tid);
-               dbg_del(tid);
+               TheList::dbg_del(tid);
                tid = ((pthread_t)-1);
 // Don't execute anything after this.
                if( autodelete ) delete this;
@@ -312,13 +237,3 @@ unsigned long Thread::get_tid()
        return tid;
 }
 
-void Thread::dump_threads(FILE *fp)
-{
-       int i = thread_list.size();
-       while( --i >= 0 ) {
-               fprintf(fp, "thread 0x%012lx, owner 0x%012lx, %s\n",
-                       (unsigned long)thread_list[i]->tid, (unsigned long)thread_list[i]->owner,
-                       thread_list[i]->name);
-       }
-}
-
index a0a597441876a1e42e27fc2e8074fee2a10f4fe6..7aeb079a22a7fff3c7e6a822f171d5090d44e3f3 100644 (file)
@@ -482,6 +482,7 @@ int VFrame::allocate_data(unsigned char *data, int shmid,
                }
                else {
 // Have to use malloc for libpng
+//printf("==vframe %d from %p\n", size, __builtin_return_address(0));
                        this->data = (unsigned char *)malloc(size);
                }
 
index dc14dc876f9e17d25df91ac68a01ae153872a7e7..dacbe712d879d8544ddb19b489bde7a2c94cdef7 100644 (file)
@@ -244,8 +244,6 @@ public:
 
 
 
-
-
 // ================================ OpenGL functions ===========================
 // Defined in vframe3d.C
 // Location of working image if OpenGL playback
index c70d6adb0d98cfe4b8b2ae423bf8d7e4b1365325..ecc02613b500c26d12383ed28cf90bf224bc7632 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * CINELERRA
- * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 1997-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
@@ -659,6 +659,7 @@ void InterpolateVideo::optic_flow()
                        }
                }
 
+//printf("InterpolateVideo::optic_flow %d %d\n", __LINE__, invalid_blocks.size());
                if(invalid_blocks.size())
                {
                        if(!blend_engine)
index 90c472a1b04a6d570a7e6222504f8f590faa824c..8335cc2e79855c89fb855b79e5b280daa8758d86 100644 (file)
@@ -106,12 +106,12 @@ void OpticFlowUnit::process_package(LoadPackage *package)
                motion->scan_frame(plugin->frames[0],
 // Frame after motion
                        plugin->frames[1],
-                       100 * plugin->config.search_radius / w,
-                       100 * plugin->config.search_radius / h,
-                       100 * plugin->config.macroblock_size / w,
-                       100 * plugin->config.macroblock_size / h,
-                       100 * mb->x / w,
-                       100 * mb->y / h,
+                       plugin->config.search_radius,
+                       plugin->config.search_radius,
+                       plugin->config.macroblock_size,
+                       plugin->config.macroblock_size,
+                       mb->x,
+                       mb->y,
                        MotionScan::TRACK_PREVIOUS,
                        MotionScan::CALCULATE,
 // Get it to do the subpixel step
@@ -119,18 +119,14 @@ void OpticFlowUnit::process_package(LoadPackage *package)
                        0,
                        0,
                        0,
-                       MIN(MAX_SEARCH_STEPS, plugin->config.search_radius * plugin->config.search_radius),
                        0,
                        0,
                        0,
+                       0,
+                       1,
+                       0,
+                       0,
                        0);
-// Degrees from center to maximum angle
-//                     0, 
-// Accumulated angle from previous frames
-//                     0,
-// Total number of angles to test in each pass
-//                     0,
-//                     0);
 
 
                mb->dx = motion->dx_result;
diff --git a/cinelerra-5.1/plugins/motion/debug b/cinelerra-5.1/plugins/motion/debug
deleted file mode 100644 (file)
index 0d24a84..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-AWindowGUI::update_assets 1
-AWindowGUI::update_assets 3
-AWindowGUI::update_assets 6 0
-AWindowGUI::update_assets 7
-AWindowGUI::update_assets 8
-mwindow.C: 2135
-mwindow.C: 2139
-mwindowgui.C: 313
-mwindowgui.C: 324
-mwindowgui.C: 337
-mwindowgui.C: 342
-mwindowgui.C: 352
-mwindow.C: 2141
-mwindow.C: 2148
-mwindow.C: 2172
-signal_entry: got SIGINT my pid=4828 execution table size=0:
-signal_entry: lock table size=1
-    0x3074c10 RemoveThread::input_lock RemoveThread::run 
-BC_Signals::dump_buffers: buffer table size=0
-BC_Signals::delete_temps: deleting 0 temp files
-SigHandler::signal_handler total files=0
-signal_entry: got SIGINT my pid=4831 execution table size=0:
-signal_entry: lock table size=1
-    0x3074c10 RemoveThread::input_lock RemoveThread::run 
-BC_Signals::dump_buffers: buffer table size=0
-BC_Signals::delete_temps: deleting 0 temp files
-SigHandler::signal_handler total files=0
-signal_entry: got SIGINT my pid=4822 execution table size=0:
-signal_entry: lock table size=1
-    0x3074c10 RemoveThread::input_lock RemoveThread::run 
-BC_Signals::dump_buffers: buffer table size=0
-BC_Signals::delete_temps: deleting 0 temp files
-SigHandler::signal_handler total files=0
-AWindowGUI::update_assets 1
-MotionScan::scan_frame 851 angle1=-15.000000 angle2=15.000000 angle_result=15.000000
-MotionScan::scan_frame 851 angle1=7.500000 angle2=22.500000 angle_result=11.250000
-MotionScan::scan_frame 851 angle1=7.500000 angle2=15.000000 angle_result=15.000000
-MotionScan::scan_frame 851 angle1=13.125000 angle2=16.875000 angle_result=14.062500
-MotionScan::scan_frame 851 angle1=13.125000 angle2=15.000000 angle_result=15.000000
-MotionScan::scan_frame 851 angle1=14.531250 angle2=15.468750 angle_result=15.234375
-MotionScan::scan_frame 802 angle1=14.882812 angle2=15.117188 angle_result=15.000000
-MotionScan::scan_frame 818 angle1=14.824219 angle2=15.058594 angle_result=14.941406
-MotionScan::scan_frame 897 dx=181.00 dy=-92.25 dangle=15.000000
-MotionMain::process_global 570 engine->dx_result=724 engine->dy_result=-369
-MotionMain::process_global 611 total_dx=724 total_dy=-369
-MotionMain::draw_vectors 1222 724 -369 512 512 693 420
-signal_entry: got SIGINT my pid=4805 execution table size=16:
-kill_subs 262: process=4809
-    mainindexes.C: add_next_asset: 133
-    mainindexes.C: add_next_asset: 135
-    mainindexes.C: add_next_asset: 137
-    mainindexes.C: add_next_asset: 73
-    mainindexes.C: add_next_asset: 79
-    mainindexes.C: add_next_asset: 82
-    mainindexes.C: add_next_asset: 92
-    mainindexes.C: add_next_asset: 98
-    mainindexes.C: add_next_asset: 109
-    mainindexes.C: add_next_asset: 112
-    mainindexes.C: add_next_asset: 118
-    mainindexes.C: add_next_asset: 133
-    mainindexes.C: add_next_asset: 135
-    mainindexes.C: add_next_asset: 137
-    resourcepixmap.C: draw_data: 419
-    resourcepixmap.C: draw_data: 422
-signal_entry: lock table size=18
-    0x3074c10 RemoveThread::input_lock RemoveThread::run 
-    0x40d5f60 CWindowTool::input_lock CWindowTool::run 
-    0x41c1440 TransportQue::output_lock PlaybackEngine::run 
-    0x41c1f50 MainIndexes::input_lock MainIndexes::run 1 
-    0x3eaa5d0 Cinelerra: Resources MWindow::update_project *
-    0x40f9360 TransportQue::output_lock PlaybackEngine::run 
-    0x41c1bd0 CICache::total_lock CICache::delete_oldest *
-    0x428a3b0 BC_Repeater::repeat_lock BC_Repeater::run 
-    0x43459c0 LoadClient::input_lock LoadClient::run 
-    0x42f5010 LoadClient::input_lock LoadClient::run 
-    0x430a610 LoadClient::input_lock LoadClient::run 
-    0x430a370 LoadClient::input_lock LoadClient::run 
-    0x4502ff0 LoadClient::input_lock LoadClient::run 
-    0x4503230 LoadClient::input_lock LoadClient::run 
-    0x4514e30 LoadClient::input_lock LoadClient::run 
-    0x4515200 LoadClient::input_lock LoadClient::run 
-    0x4508040 LoadClient::input_lock LoadClient::run 
-    0x4507da0 LoadClient::input_lock LoadClient::run 
-BC_Signals::dump_buffers: buffer table size=0
-BC_Signals::delete_temps: deleting 0 temp files
-SigHandler::signal_handler total files=0
index ed6768037e5deb70bd7d38a2bed497b226f3f76a..63d02302bbb9ae0d154c9da9d35b27b53357eb30 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2012 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
@@ -33,6 +33,7 @@
 #include "mutex.h"
 #include "overlayframe.h"
 #include "rotateframe.h"
+#include "rotatescan.h"
 #include "transportque.h"
 
 
@@ -41,7 +42,6 @@
 
 REGISTER_PLUGIN(MotionMain)
 
-
 #undef DEBUG
 
 // #ifndef DEBUG
@@ -52,48 +52,35 @@ REGISTER_PLUGIN(MotionMain)
 
 MotionConfig::MotionConfig()
 {
-       global_range_w = 10;
-       global_range_h = 10;
+       global_range_w = 5;
+       global_range_h = 5;
        rotation_range = 5;
        rotation_center = 0;
        block_count = 1;
-       global_block_w = 50; // MIN_BLOCK;
-       global_block_h = 50; // MIN_BLOCK;
+       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 = 25;
-       rotate_magnitude = 30;
-       return_speed = 8;
-       rotate_return_speed = 8;
-       action_type = MotionScan::STABILIZE_PIXEL;
-       global = 1;
+//     global_positions = 256;
+//     rotate_positions = 4;
+       magnitude = 100;
+       rotate_magnitude = 90;
+       return_speed = 0;
+       rotate_return_speed = 0;
+       action_type = MotionScan::STABILIZE;
+//     global = 1;
        rotate = 1;
-       addtrackedframeoffset = 0;
-       tracking_type = MotionScan::CALCULATE;
-       draw_vectors = 0;
-       tracking_object = MotionScan::TRACK_PREVIOUS;
+       tracking_type = MotionScan::NO_CALCULATE;
+       draw_vectors = 1;
+       tracking_object = MotionScan::TRACK_SINGLE;
        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);
@@ -114,9 +101,8 @@ int MotionConfig::equivalent(MotionConfig &that)
                rotation_range == that.rotation_range &&
                rotation_center == that.rotation_center &&
                action_type == that.action_type &&
-               global == that.global &&
+//             global == that.global &&
                rotate == that.rotate &&
-               addtrackedframeoffset == that.addtrackedframeoffset &&
                draw_vectors == that.draw_vectors &&
                block_count == that.block_count &&
                global_block_w == that.global_block_w &&
@@ -125,8 +111,8 @@ int MotionConfig::equivalent(MotionConfig &that)
 //             rotation_block_h == that.rotation_block_h &&
                EQUIV(block_x, that.block_x) &&
                EQUIV(block_y, that.block_y) &&
-               global_positions == that.global_positions &&
-               rotate_positions == that.rotate_positions &&
+//             global_positions == that.global_positions &&
+//             rotate_positions == that.rotate_positions &&
                magnitude == that.magnitude &&
                return_speed == that.return_speed &&
                rotate_return_speed == that.rotate_return_speed &&
@@ -145,16 +131,15 @@ void MotionConfig::copy_from(MotionConfig &that)
        rotation_range = that.rotation_range;
        rotation_center = that.rotation_center;
        action_type = that.action_type;
-       global = that.global;
+//     global = that.global;
        rotate = that.rotate;
-       addtrackedframeoffset = that.addtrackedframeoffset;
        tracking_type = that.tracking_type;
        draw_vectors = that.draw_vectors;
        block_count = that.block_count;
        block_x = that.block_x;
        block_y = that.block_y;
-       global_positions = that.global_positions;
-       rotate_positions = that.rotate_positions;
+//     global_positions = that.global_positions;
+//     rotate_positions = that.rotate_positions;
        global_block_w = that.global_block_w;
        global_block_h = that.global_block_h;
 //     rotation_block_w = that.rotation_block_w;
@@ -185,14 +170,13 @@ void MotionConfig::interpolate(MotionConfig &prev,
        rotation_range = prev.rotation_range;
        rotation_center = prev.rotation_center;
        action_type = prev.action_type;
-       global = prev.global;
+//     global = prev.global;
        rotate = prev.rotate;
-       addtrackedframeoffset = prev.addtrackedframeoffset;
        tracking_type = prev.tracking_type;
        draw_vectors = prev.draw_vectors;
        block_count = prev.block_count;
-       global_positions = prev.global_positions;
-       rotate_positions = prev.rotate_positions;
+//     global_positions = prev.global_positions;
+//     rotate_positions = prev.rotate_positions;
        global_block_w = prev.global_block_w;
        global_block_h = prev.global_block_h;
 //     rotation_block_w = prev.rotation_block_w;
@@ -231,7 +215,7 @@ MotionMain::MotionMain(PluginServer *server)
 {
        engine = 0;
        rotate_engine = 0;
-       motion_rotate = 0;
+//     motion_rotate = 0;
        total_dx = 0;
        total_dy = 0;
        total_angle = 0;
@@ -250,8 +234,6 @@ MotionMain::MotionMain(PluginServer *server)
        current_rotate_ref = 0;
        rotate_target_src = 0;
        rotate_target_dst = 0;
-
-       config.set_cpus(get_project_smp() + 1);
 }
 
 MotionMain::~MotionMain()
@@ -262,7 +244,7 @@ MotionMain::~MotionMain()
        delete [] search_area;
        delete temp_frame;
        delete rotate_engine;
-       delete motion_rotate;
+//     delete motion_rotate;
 
 
        delete prev_global_ref;
@@ -295,11 +277,11 @@ void MotionMain::update_gui()
                {
                        thread->window->lock_window("MotionMain::update_gui");
 
-                       char string[BCTEXTLEN];
-                       sprintf(string, "%d", config.global_positions);
-                       ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
-                       sprintf(string, "%d", config.rotate_positions);
-                       ((MotionWindow*)thread->window)->rotation_search_positions->set_text(string);
+//                     char string[BCTEXTLEN];
+//                     sprintf(string, "%d", config.global_positions);
+//                     ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
+//                     sprintf(string, "%d", config.rotate_positions);
+//                     ((MotionWindow*)thread->window)->rotation_search_positions->set_text(string);
 
                        ((MotionWindow*)thread->window)->global_block_w->update(config.global_block_w);
                        ((MotionWindow*)thread->window)->global_block_h->update(config.global_block_h);
@@ -354,8 +336,8 @@ void MotionMain::save_data(KeyFrame *keyframe)
        output.tag.set_title("MOTION");
 
        output.tag.set_property("BLOCK_COUNT", config.block_count);
-       output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
-       output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
+//     output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
+//     output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
        output.tag.set_property("GLOBAL_BLOCK_W", config.global_block_w);
        output.tag.set_property("GLOBAL_BLOCK_H", config.global_block_h);
 //     output.tag.set_property("ROTATION_BLOCK_W", config.rotation_block_w);
@@ -371,9 +353,8 @@ void MotionMain::save_data(KeyFrame *keyframe)
        output.tag.set_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
        output.tag.set_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
        output.tag.set_property("ACTION_TYPE", config.action_type);
-       output.tag.set_property("GLOBAL", config.global);
+//     output.tag.set_property("GLOBAL", config.global);
        output.tag.set_property("ROTATE", config.rotate);
-       output.tag.set_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
        output.tag.set_property("TRACKING_TYPE", config.tracking_type);
        output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
        output.tag.set_property("TRACKING_OBJECT", config.tracking_object);
@@ -404,8 +385,8 @@ void MotionMain::read_data(KeyFrame *keyframe)
                        if(input.tag.title_is("MOTION"))
                        {
                                config.block_count = input.tag.get_property("BLOCK_COUNT", config.block_count);
-                               config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
-                               config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
+//                             config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
+//                             config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
                                config.global_block_w = input.tag.get_property("GLOBAL_BLOCK_W", config.global_block_w);
                                config.global_block_h = input.tag.get_property("GLOBAL_BLOCK_H", config.global_block_h);
 //                             config.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
@@ -421,9 +402,8 @@ void MotionMain::read_data(KeyFrame *keyframe)
                                config.rotate_magnitude = input.tag.get_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
                                config.rotate_return_speed = input.tag.get_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
                                config.action_type = input.tag.get_property("ACTION_TYPE", config.action_type);
-                               config.global = input.tag.get_property("GLOBAL", config.global);
+//                             config.global = input.tag.get_property("GLOBAL", config.global);
                                config.rotate = input.tag.get_property("ROTATE", config.rotate);
-                               config.addtrackedframeoffset = input.tag.get_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
                                config.tracking_type = input.tag.get_property("TRACKING_TYPE", config.tracking_type);
                                config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
                                config.tracking_object = input.tag.get_property("TRACKING_OBJECT", config.tracking_object);
@@ -461,30 +441,39 @@ void MotionMain::allocate_temp(int w, int h, int color_model)
 
 void MotionMain::process_global()
 {
+       int w = current_global_ref->get_w();
+       int h = current_global_ref->get_h();
+
 
        if(!engine) engine = new MotionScan(PluginClient::get_project_smp() + 1,
                PluginClient::get_project_smp() + 1);
 
 // Determine if frames changed
+// printf("MotionMain::process_global %d block_y=%f total_dy=%d\n",
+//  __LINE__, config.block_y * h / 100, total_dy);
        engine->scan_frame(current_global_ref,
                prev_global_ref,
-               config.global_range_w,
-               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;
 
@@ -496,9 +485,8 @@ void MotionMain::process_global()
                total_dy = (int64_t)total_dy * (100 - config.return_speed) / 100;
                total_dx += engine->dx_result;
                total_dy += engine->dy_result;
-// printf("MotionMain::process_global total_dx=%d engine->dx_result=%d\n",
-// total_dx,
-// engine->dx_result);
+// printf("MotionMain::process_global %d total_dy=%d engine->dy_result=%d\n", 
+//  __LINE__, total_dy, engine->dy_result);
        }
        else
 // Make accumulation vector current
@@ -510,43 +498,27 @@ void MotionMain::process_global()
 // Clamp accumulation vector
        if(config.magnitude < 100)
        {
-               //int block_w = (int64_t)config.global_block_w *
-               //              current_global_ref->get_w() / 100;
-               //int block_h = (int64_t)config.global_block_h *
-               //              current_global_ref->get_h() / 100;
-               int block_x_orig = (int64_t)(config.block_x *
-                       current_global_ref->get_w() /
-                       100);
+               //int block_w = (int64_t)config.global_block_w * w / 100;
+               //int block_h = (int64_t)config.global_block_h * h / 100;
+               int block_x_orig = (int64_t)(config.block_x * w / 100);
                int block_y_orig = (int64_t)(config.block_y *
-                       current_global_ref->get_h() /
-                       100);
+                       current_global_ref->get_h() / h / 100);
 
-               int max_block_x = (int64_t)(current_global_ref->get_w() - block_x_orig) *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
-               int max_block_y = (int64_t)(current_global_ref->get_h() - block_y_orig) *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
+               int max_block_x = (int64_t)(w - block_x_orig) *
+                       OVERSAMPLE * config.magnitude / 100;
+               int max_block_y = (int64_t)(h - block_y_orig) *
+                       OVERSAMPLE * config.magnitude / 100;
                int min_block_x = (int64_t)-block_x_orig *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
+                       OVERSAMPLE * config.magnitude / 100;
                int min_block_y = (int64_t)-block_y_orig *
-                       OVERSAMPLE *
-                       config.magnitude /
-                       100;
+                       OVERSAMPLE * config.magnitude / 100;
 
                CLAMP(total_dx, min_block_x, max_block_x);
                CLAMP(total_dy, min_block_y, max_block_y);
        }
 
-#ifdef DEBUG
-printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
-(float)total_dx / OVERSAMPLE,
-(float)total_dy / OVERSAMPLE);
-#endif
+// printf("MotionMain::process_global %d total_dx=%d total_dy=%d\n", 
+//  __LINE__, total_dx, total_dy);
 
        if(config.tracking_object != MotionScan::TRACK_SINGLE && !config.rotate)
        {
@@ -575,7 +547,6 @@ printf("MotionMain::process_global 2 total_dx=%.02f total_dy=%.02f\n",
                        dx = -(int)(total_dx / OVERSAMPLE);
                        dy = -(int)(total_dy / OVERSAMPLE);
                        break;
-                       break;
                case MotionScan::TRACK:
                        interpolation = CUBIC_LINEAR;
                        dx = (float)total_dx / OVERSAMPLE;
@@ -617,9 +588,11 @@ void MotionMain::process_rotation()
        int block_x;
        int block_y;
 
+// Always require global
 // Convert the previous global reference into the previous rotation reference.
 // Convert global target destination into rotation target source.
-       if(config.global)
+//     if(config.global)
+       if(1)
        {
                if(!overlayer)
                        overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
@@ -684,17 +657,17 @@ void MotionMain::process_rotation()
 
 
 // Get rotation
-       if(!motion_rotate)
-               motion_rotate = new RotateScan(this,
-                       get_project_smp() + 1,
-                       get_project_smp() + 1);
-
-       current_angle = motion_rotate->scan_frame(prev_rotate_ref,
-               current_rotate_ref,
-               block_x,
-               block_y);
-
-
+//     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)
@@ -710,13 +683,13 @@ void MotionMain::process_rotation()
                        CLAMP(total_angle, -config.rotate_magnitude, config.rotate_magnitude);
                }
 
-               if(!config.global)
-               {
+//             if(!config.global)
+//             {
 // Transfer current reference frame to previous reference frame and update
 // counter.
-                       prev_rotate_ref->copy_from(current_rotate_ref);
-                       previous_frame_number = get_source_position();
-               }
+//                     prev_rotate_ref->copy_from(current_rotate_ref);
+//                     previous_frame_number = get_source_position();
+//             }
        }
        else
        {
@@ -768,7 +741,8 @@ printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
 
                        case MotionScan::STABILIZE:
                        case MotionScan::STABILIZE_PIXEL:
-                               if(config.global)
+//                             if(config.global)
+                               if(1)
                                {
 // Use origin of global stabilize operation
 //                                     rotate_engine->set_pivot((int)(rotate_target_dst->get_w() *
@@ -802,6 +776,7 @@ printf("MotionMain::process_rotation total_angle=%f\n", total_angle);
                }
 
 
+printf("MotionMain::process_rotation angle=%f\n", angle);
                rotate_engine->rotate(rotate_target_dst, rotate_target_src, angle);
 // overlayer->overlay(rotate_target_dst,
 //     prev_rotate_ref,
@@ -923,7 +898,7 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
        }
 
 
-       if(!config.global && !config.rotate) skip_current = 1;
+//     if(!config.global && !config.rotate) skip_current = 1;
 
 
 
@@ -959,7 +934,8 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
 
 
 // Get the global pointers.  Here we walk through the sequence of events.
-       if(config.global)
+//     if(config.global)
+       if(1)
        {
 // Assume global only.  Global reads previous frame and compares
 // with current frame to get the current translation.
@@ -1072,13 +1048,14 @@ printf("MotionMain::process_buffer %d start_position=%lld\n", __LINE__, start_po
 
 
 
-
+//PRINT_TRACE
+//printf("skip_current=%d config.global=%d\n", skip_current, config.global);
 
 
        if(!skip_current)
        {
 // Get position change from previous frame to current frame
-               if(config.global) process_global();
+               /* if(config.global) */ process_global();
 // Get rotation change from previous frame to current frame
                if(config.rotate) process_rotation();
 //frame[target_layer]->copy_from(prev_rotate_ref);
@@ -1142,18 +1119,20 @@ void MotionMain::draw_vectors(VFrame *frame)
        int search_x2, search_y2;
 
 
-       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)
                {
-                       global_x1 = (int64_t)(config.block_x *
-                               w /
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
                                100);
                        global_y1 = (int64_t)(config.block_y *
-                               h /
+                               h / 
                                100);
                        global_x2 = global_x1 + total_dx / OVERSAMPLE;
                        global_y2 = global_y1 + total_dy / OVERSAMPLE;
@@ -1164,34 +1143,34 @@ void MotionMain::draw_vectors(VFrame *frame)
 // End of vector is current change.
                if(config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK)
                {
-                       global_x1 = (int64_t)(config.block_x *
-                               w /
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
                                100);
                        global_y1 = (int64_t)(config.block_y *
-                               h /
+                               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) /
+                       global_x1 = (int64_t)(config.block_x * 
+                               w / 
+                               100 + 
+                               (total_dx - current_dx) / 
                                OVERSAMPLE);
                        global_y1 = (int64_t)(config.block_y *
-                               h /
+                               h / 
                                100 +
                                (total_dy - current_dy) /
                                OVERSAMPLE);
-                       global_x2 = (int64_t)(config.block_x *
-                               w /
-                               100 +
-                               total_dx /
+                       global_x2 = (int64_t)(config.block_x * 
+                               w / 
+                               100 + 
+                               total_dx / 
                                OVERSAMPLE);
                        global_y2 = (int64_t)(config.block_y *
-                               h /
+                               h / 
                                100 +
                                total_dy /
                                OVERSAMPLE);
@@ -1226,8 +1205,8 @@ void MotionMain::draw_vectors(VFrame *frame)
 // search_x2,
 // search_y2);
 
-               MotionScan::clamp_scan(w,
-                       h,
+               MotionScan::clamp_scan(w, 
+                       h, 
                        &block_x1,
                        &block_y1,
                        &block_x2,
@@ -1459,439 +1438,3 @@ void MotionMain::draw_arrow(VFrame *frame, int x1, int y1, int x2, int y2)
 
 
 
-
-
-
-
-
-
-
-
-
-RotateScanPackage::RotateScanPackage()
-{
-}
-
-
-RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
- : LoadClient(server)
-{
-       this->server = server;
-       this->plugin = plugin;
-       rotater = 0;
-       temp = 0;
-}
-
-RotateScanUnit::~RotateScanUnit()
-{
-       delete rotater;
-       delete temp;
-}
-
-void RotateScanUnit::process_package(LoadPackage *package)
-{
-       if(server->skip) return;
-       RotateScanPackage *pkg = (RotateScanPackage*)package;
-
-       if((pkg->difference = server->get_cache(pkg->angle)) < 0)
-       {
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-               int color_model = server->previous_frame->get_color_model();
-               int pixel_size = BC_CModels::calculate_pixelsize(color_model);
-               int row_bytes = server->previous_frame->get_bytes_per_line();
-
-               if(!rotater)
-                       rotater = new AffineEngine(1, 1);
-               if(!temp) temp = new VFrame(0,
-                       -1,
-                       server->previous_frame->get_w(),
-                       server->previous_frame->get_h(),
-                       color_model,
-                       -1);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-
-
-// Rotate original block size
-//             rotater->set_viewport(server->block_x1,
-//                     server->block_y1,
-//                     server->block_x2 - server->block_x1,
-//                     server->block_y2 - server->block_y1);
-               rotater->set_in_viewport(server->block_x1,
-                       server->block_y1,
-                       server->block_x2 - server->block_x1,
-                       server->block_y2 - server->block_y1);
-               rotater->set_out_viewport(server->block_x1,
-                       server->block_y1,
-                       server->block_x2 - server->block_x1,
-                       server->block_y2 - server->block_y1);
-//             rotater->set_pivot(server->block_x, server->block_y);
-               rotater->set_in_pivot(server->block_x, server->block_y);
-               rotater->set_out_pivot(server->block_x, server->block_y);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-               rotater->rotate(temp,
-                       server->previous_frame,
-                       pkg->angle);
-
-// Scan reduced block size
-//plugin->output_frame->copy_from(server->current_frame);
-//plugin->output_frame->copy_from(temp);
-// printf("RotateScanUnit::process_package %d %d %d %d %d\n",
-// __LINE__,
-// server->scan_x,
-// server->scan_y,
-// server->scan_w,
-// server->scan_h);
-// Clamp coordinates
-               int x1 = server->scan_x;
-               int y1 = server->scan_y;
-               int x2 = x1 + server->scan_w;
-               int y2 = y1 + server->scan_h;
-               x2 = MIN(temp->get_w(), x2);
-               y2 = MIN(temp->get_h(), y2);
-               x2 = MIN(server->current_frame->get_w(), x2);
-               y2 = MIN(server->current_frame->get_h(), y2);
-               x1 = MAX(0, x1);
-               y1 = MAX(0, y1);
-
-               if(x2 > x1 && y2 > y1)
-               {
-                       pkg->difference = MotionScan::abs_diff(
-                               temp->get_rows()[y1] + x1 * pixel_size,
-                               server->current_frame->get_rows()[y1] + x1 * pixel_size,
-                               row_bytes,
-                               x2 - x1,
-                               y2 - y1,
-                               color_model);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-                       server->put_cache(pkg->angle, pkg->difference);
-               }
-#if 0
-       VFrame png(x2-x1, y2-y1, BC_RGB888, -1);
-       png.transfer_from(temp, 0, x1, y1, x2-x1, y2-y1);
-       char fn[64];
-       sprintf(fn,"%s%f.png","/tmp/temp",pkg->angle); png.write_png(fn);
-       png.transfer_from(server->current_frame, 0, x1, y1, x2-x1, y2-y1);
-       sprintf(fn,"%s%f.png","/tmp/curr",pkg->angle); png.write_png(fn);
-printf("RotateScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%jd\n",
- server->block_x1, server->block_y1, server->block_x2 - server->block_x1, server->block_y2 - server->block_y1,
- server->block_x,  server->block_y,  pkg->angle,  server->scan_w, server->scan_h, pkg->difference);
-#endif
-       }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-RotateScan::RotateScan(MotionMain *plugin,
-       int total_clients,
-       int total_packages)
- : LoadServer(
-//1, 1
-total_clients, total_packages
-)
-{
-       this->plugin = plugin;
-       cache_lock = new Mutex("RotateScan::cache_lock");
-}
-
-
-RotateScan::~RotateScan()
-{
-       delete cache_lock;
-}
-
-void RotateScan::init_packages()
-{
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
-               pkg->angle = i *
-                       (scan_angle2 - scan_angle1) /
-                       (total_steps - 1) +
-                       scan_angle1;
-       }
-}
-
-LoadClient* RotateScan::new_client()
-{
-       return new RotateScanUnit(this, plugin);
-}
-
-LoadPackage* RotateScan::new_package()
-{
-       return new RotateScanPackage;
-}
-
-
-float RotateScan::scan_frame(VFrame *previous_frame,
-       VFrame *current_frame,
-       int block_x,
-       int block_y)
-{
-       skip = 0;
-       this->block_x = block_x;
-       this->block_y = block_y;
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
-       switch(plugin->config.tracking_type)
-       {
-               case MotionScan::NO_CALCULATE:
-                       result = plugin->config.rotation_center;
-                       skip = 1;
-                       break;
-
-               case MotionScan::LOAD:
-               {
-                       char string[BCTEXTLEN];
-                       sprintf(string, "%s%06jd",
-                                ROTATION_FILE, plugin->get_source_position());
-                       FILE *input = fopen(string, "r");
-                       if(input)
-                       {
-                               fscanf(input, "%f", &result);
-                               fclose(input);
-                               skip = 1;
-                       }
-                       else
-                       {
-                               perror("RotateScan::scan_frame LOAD");
-                       }
-                       break;
-               }
-       }
-
-
-
-
-
-
-
-
-       this->previous_frame = previous_frame;
-       this->current_frame = current_frame;
-       int w = current_frame->get_w();
-       int h = current_frame->get_h();
-       int block_w = w * plugin->config.global_block_w / 100;
-       int block_h = h * plugin->config.global_block_h / 100;
-
-       if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
-       if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
-       if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
-       if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
-
-       block_x1 = this->block_x - block_w / 2;
-       block_x2 = this->block_x + block_w / 2;
-       block_y1 = this->block_y - block_h / 2;
-       block_y2 = this->block_y + block_h / 2;
-
-// Calculate the maximum area available to scan after rotation.
-// Must be calculated from the starting range because of cache.
-// Get coords of rectangle after rotation.
-       double center_x = this->block_x;
-       double center_y = this->block_y;
-       double max_angle = plugin->config.rotation_range;
-       double base_angle1 = atan((float)block_h / block_w);
-       double base_angle2 = atan((float)block_w / block_h);
-       double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
-       double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
-       double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
-       double x1 = center_x - cos(target_angle1) * radius;
-       double y1 = center_y - sin(target_angle1) * radius;
-       double x2 = center_x + sin(target_angle2) * radius;
-       double y2 = center_y - cos(target_angle2) * radius;
-       double x3 = center_x - sin(target_angle2) * radius;
-       double y3 = center_y + cos(target_angle2) * radius;
-
-// Track top edge to find greatest area.
-       double max_area1 = 0;
-       //double max_x1 = 0;
-       double max_y1 = 0;
-       for(double x = x1; x < x2; x++)
-       {
-               double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
-               if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
-               {
-                       double area = fabs(x - center_x) * fabs(y - center_y);
-                       if(area > max_area1)
-                       {
-                               max_area1 = area;
-                               //max_x1 = x;
-                               max_y1 = y;
-                       }
-               }
-       }
-
-// Track left edge to find greatest area.
-       double max_area2 = 0;
-       double max_x2 = 0;
-       //double max_y2 = 0;
-       for(double y = y1; y < y3; y++)
-       {
-               double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
-               if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
-               {
-                       double area = fabs(x - center_x) * fabs(y - center_y);
-                       if(area > max_area2)
-                       {
-                               max_area2 = area;
-                               max_x2 = x;
-                               //max_y2 = y;
-                       }
-               }
-       }
-
-       double max_x, max_y;
-       max_x = max_x2;
-       max_y = max_y1;
-
-// Get reduced scan coords
-       scan_w = (int)(fabs(max_x - center_x) * 2);
-       scan_h = (int)(fabs(max_y - center_y) * 2);
-       scan_x = (int)(center_x - scan_w / 2);
-       scan_y = (int)(center_y - scan_h / 2);
-// printf("RotateScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n",
-// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
-// printf("    angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
-
-// Determine min angle from size of block
-       double angle1 = atan((double)block_h / block_w);
-       double angle2 = atan((double)(block_h - 1) / (block_w + 1));
-       double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
-       min_angle = MAX(min_angle, MIN_ANGLE);
-
-//printf("RotateScan::scan_frame %d min_angle=%f\n", __LINE__, min_angle * 360 / 2 / M_PI);
-
-       cache.remove_all_objects();
-
-
-       if(!skip)
-       {
-               if(previous_frame->data_matches(current_frame))
-               {
-//printf("RotateScan::scan_frame: frames match.  Skipping.\n");
-                       result = plugin->config.rotation_center;
-                       skip = 1;
-               }
-       }
-
-       if(!skip)
-       {
-// Initial search range
-               float angle_range = max_angle;
-               result = plugin->config.rotation_center;
-               total_steps = plugin->config.rotate_positions;
-
-
-               while(angle_range >= min_angle * total_steps)
-               {
-                       scan_angle1 = result - angle_range;
-                       scan_angle2 = result + angle_range;
-
-
-                       set_package_count(total_steps);
-//set_package_count(1);
-                       process_packages();
-
-                       int64_t min_difference = -1;
-                       for(int i = 0; i < get_total_packages(); i++)
-                       {
-                               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
-                               if(pkg->difference < min_difference || min_difference == -1)
-                               {
-                                       min_difference = pkg->difference;
-                                       result = pkg->angle;
-                               }
-//break;
-                       }
-
-                       angle_range /= 2;
-
-//break;
-               }
-       }
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
-
-       if(!skip && plugin->config.tracking_type == MotionScan::SAVE)
-       {
-               char string[BCTEXTLEN];
-               sprintf(string, "%s%06jd",
-                       ROTATION_FILE, plugin->get_source_position());
-               FILE *output = fopen(string, "w");
-               if(output)
-               {
-                       fprintf(output, "%f\n", result);
-                       fclose(output);
-               }
-               else
-               {
-                       perror("RotateScan::scan_frame SAVE");
-               }
-       }
-
-//printf("RotateScan::scan_frame %d angle=%f\n", __LINE__, result);
-
-
-
-       return result;
-}
-
-int64_t RotateScan::get_cache(float angle)
-{
-       int64_t result = -1;
-       cache_lock->lock("RotateScan::get_cache");
-       for(int i = 0; i < cache.total; i++)
-       {
-               RotateScanCache *ptr = cache.values[i];
-               if(fabs(ptr->angle - angle) <= MIN_ANGLE)
-               {
-                       result = ptr->difference;
-                       break;
-               }
-       }
-       cache_lock->unlock();
-       return result;
-}
-
-void RotateScan::put_cache(float angle, int64_t difference)
-{
-       RotateScanCache *ptr = new RotateScanCache(angle, difference);
-       cache_lock->lock("RotateScan::put_cache");
-       cache.append(ptr);
-       cache_lock->unlock();
-}
-
-
-
-
-
-
-
-
-
-RotateScanCache::RotateScanCache(float angle, int64_t difference)
-{
-       this->angle = angle;
-       this->difference = difference;
-}
-
-
-
index e0011d751171bc8707ee32361650a65692c25a47..3ab5e7a6770a8fe13373ae57df6246ad39d6752a 100644 (file)
@@ -1,8 +1,8 @@
 
 /*
  * 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
  * the Free Software Foundation; either version 2 of the License, or
 #include "motionwindow.inc"
 #include "overlayframe.inc"
 #include "pluginvclient.h"
-#include "rotateframe.inc"
+#include "rotatescan.inc"
 #include "vframe.inc"
 
 class MotionMain;
 class MotionWindow;
-class RotateScan;
 
 
 
@@ -64,7 +63,6 @@ class RotateScan;
 // Precision of rotation
 #define MIN_ANGLE 0.0001
 
-#define ROTATION_FILE "/tmp/r"
 
 class MotionConfig
 {
@@ -79,7 +77,6 @@ public:
                int64_t next_frame,
                int64_t current_frame);
        void boundaries();
-       void set_cpus(int cpus);
 
        int block_count;
        int global_range_w;
@@ -99,8 +96,8 @@ public:
 //     int rotation_block_w;
 //     int rotation_block_h;
 // Number of search positions in each refinement of the log search
-       int global_positions;
-       int rotate_positions;
+//     int global_positions;
+//     int rotate_positions;
 // Block position in percentage 0 - 100
        double block_x;
        double block_y;
@@ -109,7 +106,6 @@ public:
        int vertical_only;
        int global;
        int rotate;
-       int addtrackedframeoffset;
 // Track or stabilize, single pixel, scan only, or nothing
        int action_type;
 // Recalculate, no calculate, save, or load coordinates from disk
@@ -182,7 +178,7 @@ public:
 // It is moved to compensate for motion and copied to the previous_frame.
        VFrame *temp_frame;
        MotionScan *engine;
-       RotateScan *motion_rotate;
+//     RotateScan *motion_rotate;
        OverlayFrame *overlayer;
        AffineEngine *rotate_engine;
 
@@ -248,110 +244,6 @@ public:
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-class RotateScanPackage : public LoadPackage
-{
-public:
-       RotateScanPackage();
-       float angle;
-       int64_t difference;
-};
-
-class RotateScanCache
-{
-public:
-       RotateScanCache(float angle, int64_t difference);
-       float angle;
-       int64_t difference;
-};
-
-class RotateScanUnit : public LoadClient
-{
-public:
-       RotateScanUnit(RotateScan *server, MotionMain *plugin);
-       ~RotateScanUnit();
-
-       void process_package(LoadPackage *package);
-
-       RotateScan *server;
-       MotionMain *plugin;
-       AffineEngine *rotater;
-       VFrame *temp;
-};
-
-class RotateScan : public LoadServer
-{
-public:
-       RotateScan(MotionMain *plugin,
-               int total_clients,
-               int total_packages);
-       ~RotateScan();
-
-       friend class RotateScanUnit;
-
-       void init_packages();
-       LoadClient* new_client();
-       LoadPackage* new_package();
-
-// Invoke the motion engine for a search
-// Frame before rotation
-       float scan_frame(VFrame *previous_frame,
-// Frame after rotation
-               VFrame *current_frame,
-// Pivot
-               int block_x,
-               int block_y);
-       int64_t get_cache(float angle);
-       void put_cache(float angle, int64_t difference);
-
-
-// Angle result
-       float result;
-
-private:
-       VFrame *previous_frame;
-// Frame after motion
-       VFrame *current_frame;
-
-       MotionMain *plugin;
-       int skip;
-
-// Pivot
-       int block_x;
-       int block_y;
-// Block to rotate
-       int block_x1;
-       int block_x2;
-       int block_y1;
-       int block_y2;
-// Area to compare
-       int scan_x;
-       int scan_y;
-       int scan_w;
-       int scan_h;
-// Range of angles to compare
-       float scan_angle1, scan_angle2;
-       int total_steps;
-
-       ArrayList<RotateScanCache*> cache;
-       Mutex *cache_lock;
-};
-
-
-
-
 #endif
 
 
index b1a533ef850477a9c7412d39e92c45d5d60c2a09..4ec92da4498fbe6e2753ae1071fc2006e9373443 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2012 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 "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()
@@ -49,156 +57,137 @@ 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)
+void MotionScanUnit::single_pixel(MotionScanPackage *pkg)
 {
-       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);
 
-
-
-
-
-
-
-
-
-
-
-// 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);
+       unsigned char *prev_ptr = server->previous_frame->get_rows()[
+               pkg->search_y] +
+               pkg->search_x * pixel_size;
+       unsigned char *current_ptr = 0;
 
-// 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);
-               }
+       if(server->do_rotate)
+       {
+               current_ptr = server->rotated_current[pkg->angle_step]->get_rows()[
+                       pkg->block_y1] + 
+                       pkg->block_x1 * pixel_size;
        }
-
-
-
-
-
-
-
        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()[
+               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);
+       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->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);
+       }
+       else
+// Sub pixel
+       {
+               subpixel(pkg);
+       }
 
 
 
 
+}
 
 
 
 
 
 
-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();
-}
 
 
 
@@ -213,75 +202,129 @@ void MotionScanUnit::put_cache(int x, int y, int64_t difference)
 MotionScan::MotionScan(int total_clients,
        int total_packages)
  : LoadServer(
+// DEBUG
 //1, 1 
 total_clients, total_packages 
 )
 {
        test_match = 1;
-       cache_lock = new Mutex("MotionScan::cache_lock");
        downsampled_previous = 0;
        downsampled_current = 0;
-//     downsample = 0;
+       rotated_current = 0;
+       rotater = 0;
 }
 
 MotionScan::~MotionScan()
 {
-       delete cache_lock;
        delete downsampled_previous;
        delete downsampled_current;
-//     delete downsample;
+       if(rotated_current)
+       {
+               for(int i = 0; i < total_rotated; i++)
+               {
+                       delete rotated_current[i];
+               }
+               
+               delete [] rotated_current;
+       }
+       delete rotater;
 }
 
 
 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 = 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->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)
                {
-                       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;
+                       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->sub_x = 0;
                        pkg->sub_y = 0;
                }
                else
                {
-                       pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
-                       pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
+                       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;
-                       }
+//                     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->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;
 
@@ -312,36 +355,727 @@ LoadClient* MotionScan::new_client()
        return new MotionScanUnit(this);
 }
 
-LoadPackage* MotionScan::new_package()
-{
-       return new MotionScanPackage;
-}
+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
+}
+
+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])
+                       {
+                               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__);
+                       }
+
+
+                       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("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();
+               
+               
+               
+               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", 
+// __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("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);
+                       }
+               }
+       }
+
+
+// printf("MotionScan::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 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;
+
+
+// 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;
 
-void MotionScan::set_test_match(int value)
-{
-       this->test_match = value;
+                       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::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 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_steps,
        int total_dx,
        int total_dy,
        int global_origin_x,
-       int global_origin_y)
+       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;
@@ -351,25 +1085,51 @@ void MotionScan::scan_frame(VFrame *previous_frame,
        this->current_frame = current_frame_arg;
        this->global_origin_x = global_origin_x;
        this->global_origin_y = global_origin_y;
-       subpixel = 0;
+       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;
 
-       cache.remove_all_objects();
+//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;
 
 // 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;
+       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);
 
 // 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);
+       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.
@@ -389,6 +1149,7 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                case MotionScan::NO_CALCULATE:
                        dx_result = 0;
                        dy_result = 0;
+                       dr_result = rotation_center;
                        skip = 1;
                        break;
 
@@ -396,21 +1157,55 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                {
 // Load result from disk
                        char string[BCTEXTLEN];
-                       sprintf(string, "%s%06d", 
-                               MOTION_FILE, 
-                               source_position);
-//printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
-                       FILE *input = fopen(string, "r");
-                       if(input)
+
+                       skip = 1;
+                       if(do_motion)
                        {
-                               (void)fscanf(input, "%d %d", 
-                                       &dx_result, &dy_result);
+                               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);
 // HACK
 //dx_result *= 2;
 //dy_result *= 2;
 //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
-                               fclose(input);
-                               skip = 1;
+                                       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;
+                               }
                        }
                        break;
                }
@@ -421,6 +1216,8 @@ void MotionScan::scan_frame(VFrame *previous_frame,
                        break;
        }
 
+
+
        if(!skip && test_match)
        {
                if(previous_frame->data_matches(current_frame))
@@ -428,19 +1225,21 @@ void MotionScan::scan_frame(VFrame *previous_frame,
 printf("MotionScan::scan_frame: data matches. skipping.\n");
                        dx_result = 0;
                        dy_result = 0;
+                       dr_result = rotation_center;
                        skip = 1;
                }
        }
 
+
 // Perform scan
        if(!skip)
        {
-//printf("MotionScan::scan_frame %d\n", __LINE__);
 // Location of block in current frame
-               int origin_offset_x = this->global_origin_x * w / 100;
-               int origin_offset_y = this->global_origin_y * h / 100;
+               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("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
 // block_x1 + block_w / 2,
@@ -452,32 +1251,31 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // block_x2,
 // block_y2);
 
-               while(1)
+               while(!failed)
                {
-// 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 1 %d %d %d %d %d %d %d %d\n",
+//                     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__, 
 // block_x1,
 // block_y1,
 // block_x2,
@@ -486,6 +1284,8 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // scan_y1,
 // scan_x2,
 // scan_y2);
+
+
 // Clamp the block coords before the scan so we get useful scan coords.
                        clamp_scan(w, 
                                h, 
@@ -498,7 +1298,9 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                                &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", 
+
+
+// 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", 
 // __LINE__,
 // block_x1,
 // block_y1,
@@ -510,6 +1312,7 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // scan_y2, 
 // x_result, 
 // y_result);
+//if(y_result == 88) exit(0);
 
 
 // Give up if invalid coords.
@@ -517,179 +1320,49 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
                                scan_x2 <= scan_x1 ||
                                block_x2 <= block_x1 ||
                                block_y2 <= block_y1)
+                       {
                                break;
+                       }
 
 // For subpixel, the top row and left column are skipped
                        if(subpixel)
                        {
 
-//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);
-                                       }
-                               }
+                               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);
 
                                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)
+                               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);
+                               
+                               if(failed)
                                {
-                                       x_steps = scan_x2 - scan_x1;
-                                       y_steps = scan_y2 - scan_y1;
+                                       dr_result = 0;
+                                       dx_result = 0;
+                                       dy_result = 0;
                                }
                                else
+                               if(current_downsample <= 1)
                                {
-                                       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.
+                       // 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;
+//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;
                                                subpixel = 1;
                                        }
                                        else
@@ -697,62 +1370,110 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 // Fill in results and quit
                                                dx_result = block_x1 * OVERSAMPLE - x_result;
                                                dy_result = block_y1 * OVERSAMPLE - y_result;
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_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;
+//                                     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
                                        x_result /= OVERSAMPLE;
                                        y_result /= OVERSAMPLE;
+// debug
+//exit(1);
                                }
+
                        }
                }
 
                dx_result *= -1;
                dy_result *= -1;
+               dr_result *= -1;
        }
-//printf("MotionScan::scan_frame %d\n", __LINE__);
-
+// printf("MotionScan::scan_frame %d dx=%f dy=%f dr=%f\n", 
+// __LINE__, 
+// (float)dx_result / OVERSAMPLE, 
+// (float)dy_result / OVERSAMPLE, 
+// dr_result);
 
-       if(vertical_only) dx_result = 0;
-       if(horizontal_only) dy_result = 0;
 
 
 
 // Write results
-       if(tracking_type == MotionScan::SAVE)
+       if(!skip && tracking_type == MotionScan::SAVE)
        {
                char string[BCTEXTLEN];
-               sprintf(string, 
-                       "%s%06d", 
-                       MOTION_FILE, 
-                       source_position);
-               FILE *output = fopen(string, "w");
-               if(output)
+               
+               
+               if(do_motion)
                {
-                       fprintf(output, 
-                               "%d %d\n",
-                               dx_result,
-                               dy_result);
-                       fclose(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__);
+                       }
                }
-               else
+               
+               if(do_rotate)
                {
-                       printf("MotionScan::scan_frame %d: save coordinate failed", __LINE__);
+                       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 dx=%.2f dy=%.2f\n", 
-// __LINE__,
-// (float)this->dx_result / OVERSAMPLE,
-// (float)this->dy_result / OVERSAMPLE);
-}
 
+       if(vertical_only) dx_result = 0;
+       if(horizontal_only) dy_result = 0;
 
+// printf("MotionScan::scan_frame %d dx=%d dy=%d\n", 
+// __LINE__,
+// this->dx_result,
+// this->dy_result);
+}
 
 
 
@@ -768,30 +1489,7 @@ printf("MotionScan::scan_frame: data matches. skipping.\n");
 
 
 
-int64_t MotionScan::get_cache(int x, int y)
-{
-       int64_t result = -1;
-       cache_lock->lock("MotionScan::get_cache");
-       for(int i = 0; i < cache.total; i++)
-       {
-               MotionScanCache *ptr = cache.values[i];
-               if(ptr->x == x && ptr->y == y)
-               {
-                       result = ptr->difference;
-                       break;
-               }
-       }
-       cache_lock->unlock();
-       return result;
-}
 
-void MotionScan::put_cache(int x, int y, int64_t difference)
-{
-       MotionScanCache *ptr = new MotionScanCache(x, y, difference);
-       cache_lock->lock("MotionScan::put_cache");
-       cache.append(ptr);
-       cache_lock->unlock();
-}
 
 
 
@@ -808,10 +1506,8 @@ void MotionScan::put_cache(int x, int y, int64_t difference)
                        { \
                                temp_type difference; \
                                difference = *prev_row++ - *current_row++; \
-                               if(difference < 0) \
-                                       result_temp -= difference; \
-                               else \
-                                       result_temp += difference; \
+                               difference *= difference; \
+                               result_temp += difference; \
                        } \
                        if(components == 4) \
                        { \
@@ -853,12 +1549,6 @@ int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
                case BC_YUVA8888:
                        ABS_DIFF(unsigned char, int64_t, 1, 4)
                        break;
-               case BC_YUV161616:
-                       ABS_DIFF(uint16_t, int64_t, 1, 3)
-                       break;
-               case BC_YUVA16161616:
-                       ABS_DIFF(uint16_t, int64_t, 1, 4)
-                       break;
        }
        return result;
 }
@@ -893,10 +1583,8 @@ int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
                                        0x100 / 0x100; \
                                temp_type current_value = *current_row++; \
                                difference = prev_value - current_value; \
-                               if(difference < 0) \
-                                       result_temp -= difference; \
-                               else \
-                                       result_temp += difference; \
+                               difference *= difference; \
+                               result_temp += difference; \
                        } \
  \
 /* skip alpha */ \
@@ -951,29 +1639,159 @@ int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
                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)
+       }
+       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)
                        break;
-               case BC_YUVA16161616:
-                       ABS_DIFF_SUB(uint16_t, int64_t, 1, 4)
+               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("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]; \
+       } \
+ \
+}
 
-MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
+double MotionScan::calculate_range(unsigned char *current_ptr,
+       int row_bytes,
+       int w,
+       int h,
+       int color_model)
 {
-       this->x = x;
-       this->y = y;
-       this->difference = 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;
 }
 
 
+//#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, 
        int *block_x1,
@@ -1006,29 +1824,37 @@ void MotionScan::clamp_scan(int w,
 // scan is always out of range before block.
                if(*scan_x1 < 0)
                {
-//                     int difference = -*scan_x1;
-//                     *block_x1 += difference;
+#ifdef CLAMP_BLOCK
+                       int difference = -*scan_x1;
+                       *block_x1 += difference;
+#endif
                        *scan_x1 = 0;
                }
 
                if(*scan_y1 < 0)
                {
-//                     int difference = -*scan_y1;
-//                     *block_y1 += difference;
+#ifdef CLAMP_BLOCK
+                       int difference = -*scan_y1;
+                       *block_y1 += difference;
+#endif
                        *scan_y1 = 0;
                }
 
                if(*scan_x2 > w)
                {
                        int difference = *scan_x2 - w;
-//                     *block_x2 -= difference;
+#ifdef CLAMP_BLOCK
+                       *block_x2 -= difference;
+#endif
                        *scan_x2 -= difference;
                }
 
                if(*scan_y2 > h)
                {
                        int difference = *scan_y2 - h;
-//                     *block_y2 -= difference;
+#ifdef CLAMP_BLOCK
+                       *block_y2 -= difference;
+#endif
                        *scan_y2 -= difference;
                }
 
@@ -1044,7 +1870,9 @@ void MotionScan::clamp_scan(int w,
                if(*scan_x1 < 0)
                {
                        int difference = -*scan_x1;
-//                     *block_x1 += difference;
+#ifdef CLAMP_BLOCK
+                       *block_x1 += difference;
+#endif
                        *scan_x2 += difference;
                        *scan_x1 = 0;
                }
@@ -1052,7 +1880,9 @@ void MotionScan::clamp_scan(int w,
                if(*scan_y1 < 0)
                {
                        int difference = -*scan_y1;
-//                     *block_y1 += difference;
+#ifdef CLAMP_BLOCK
+                       *block_y1 += difference;
+#endif
                        *scan_y2 += difference;
                        *scan_y1 = 0;
                }
@@ -1061,14 +1891,18 @@ void MotionScan::clamp_scan(int w,
                {
                        int difference = *scan_x2 - *block_x1 + *block_x2 - w;
                        *scan_x2 -= difference;
-//                     *block_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;
-//                     *block_y2 -= difference;
+#ifdef CLAMP_BLOCK
+                       *block_y2 -= difference;
+#endif
                }
 
 //             CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
index 8e756ee38e2297f6839943453651284e4d15afbf..f358531f09e665ed19d85acf1fab6e986ca30a49 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,8 +23,7 @@
 #define MOTIONSCAN_H
 
 
-#include "arraylist.h"
-//#include "../downsample/downsampleengine.inc"
+#include "affine.inc"
 #include "loadbalance.h"
 #include "vframe.inc"
 #include <stdint.h>
@@ -33,6 +32,7 @@ class MotionScan;
 
 #define OVERSAMPLE 4
 #define MOTION_FILE "/tmp/m"
+#define ROTATION_FILE "/tmp/r"
 
 class MotionScanPackage : public LoadPackage
 {
@@ -40,10 +40,11 @@ public:
        MotionScanPackage();
 
 // For multiple blocks
-// Position of stationary block
+// Position of stationary block after downsampling
        int block_x1, block_y1, block_x2, block_y2;
-// Range of positions to scan
-       int scan_x1, scan_y1, scan_x2, scan_y2;
+// index of rotated frame
+       int angle_step;
+
        int dx;
        int dy;
        int64_t max_difference;
@@ -51,11 +52,9 @@ public:
        int64_t min_pixel;
        int is_border;
        int valid;
-// For single block
-       int step;
        int64_t difference1;
        int64_t difference2;
-// Search position to nearest pixel
+// Search position of current package to nearest pixel with downsampling
        int search_x;
        int search_y;
 // Subpixel of search position
@@ -63,14 +62,6 @@ public:
        int sub_y;
 };
 
-class MotionScanCache
-{
-public:
-       MotionScanCache(int x, int y, int64_t difference);
-       int x, y;
-       int64_t difference;
-};
-
 class MotionScanUnit : public LoadClient
 {
 public:
@@ -78,13 +69,10 @@ public:
        ~MotionScanUnit();
 
        void process_package(LoadPackage *package);
-       int64_t get_cache(int x, int y);
-       void put_cache(int x, int y, int64_t difference);
+       void subpixel(MotionScanPackage *pkg);
+       void single_pixel(MotionScanPackage *pkg);
 
        MotionScan *server;
-
-       ArrayList<MotionScanCache*> cache;
-       Mutex *cache_lock;
 };
 
 class MotionScan : public LoadServer
@@ -105,27 +93,27 @@ public:
 // Invoke the motion engine for a search
 // Frame before motion
        void scan_frame(VFrame *previous_frame,
-// Frame after motion
                VFrame *current_frame,
-               int global_range_w,
+               int global_range_w, // in pixels
                int global_range_h,
-               int global_block_w,
+               int global_block_w, // in pixels
                int global_block_h,
-               double block_x,
-               double block_y,
+               int block_x, // in pixels
+               int block_y,
                int frame_type,
                int tracking_type,
                int action_type,
                int horizontal_only,
                int vertical_only,
                int source_position,
-               int total_steps,
-               int total_dx,
+               int total_dx, // in pixels * OVERSAMPLE
                int total_dy,
-               int global_origin_x,
-               int global_origin_y);
-       int64_t get_cache(int x, int y);
-       void put_cache(int x, int y, int64_t difference);
+               int global_origin_x, // in pixels
+               int global_origin_y,
+               int do_motion,
+               int do_rotate,
+               double rotation_center, // in deg
+               double rotation_range);
 
        static int64_t abs_diff(unsigned char *prev_ptr,
                unsigned char *current_ptr,
@@ -159,6 +147,7 @@ public:
 // OVERSAMPLE
        int dx_result;
        int dy_result;
+       float dr_result;
 
        enum
        {
@@ -188,6 +177,27 @@ public:
        };
 
 private:
+       void downsample_frame(VFrame *dst, 
+               VFrame *src, 
+               int downsample);
+       void pixel_search(int &x_result, int &y_result, double &r_result);
+       void subpixel_search(int &x_result, int &y_result);
+       double step_to_angle(int step, double center);
+
+//     double calculate_variance(unsigned char *current_ptr,
+//             int row_bytes,
+//             int w,
+//             int h,
+//             int color_model);
+       double calculate_range(unsigned char *current_ptr,
+               int row_bytes,
+               int w,
+               int h,
+               int color_model);
+
+
+
+       AffineEngine *rotater;
 // Pointer to downsampled frame before motion
        VFrame *previous_frame;
 // Pointer to downsampled frame after motion
@@ -198,33 +208,49 @@ private:
 // Downsampled frames
        VFrame *downsampled_previous;
        VFrame *downsampled_current;
+// rotated versions of current_frame
+       VFrame **rotated_current;
+// allocation of rotated_current array, a copy of angle_steps
+       int total_rotated;
 // Test for identical frames before processing
 // Faster to skip it if the frames are usually different
        int test_match;
        int skip;
+// macroblocks didn't have enough data
+       int failed;
 // For single block
        int block_x1;
        int block_x2;
        int block_y1;
        int block_y2;
+       int scan_w;
+       int scan_h;
        int scan_x1;
        int scan_y1;
        int scan_x2;
        int scan_y2;
-       int total_pixels;
-       int total_steps;
-       int edge_steps;
+       double scan_angle1, scan_angle2;
        int y_steps;
        int x_steps;
+       int angle_steps;
+// in deg
+       double angle_step;
        int subpixel;
        int horizontal_only;
        int vertical_only;
        int global_origin_x;
        int global_origin_y;
-
-       ArrayList<MotionScanCache*> cache;
-       Mutex *cache_lock;
-//     DownSampleServer *downsample;
+       int action_type;
+       int current_downsample;
+       int downsampled_w;
+       int downsampled_h;
+       int total_steps;
+       int do_motion;
+       int do_rotate;
+       int rotation_pass;
+// in deg
+       double rotation_center;
+       double rotation_range;
 };
 
 
index 02972d15b1cbef590c20c6cb537b07387d1f1a96..289db8348a64eb148a3fd46dcf860300f4112a42 100644 (file)
@@ -53,10 +53,10 @@ void MotionWindow::create_objects()
 
 
 
-       add_subwindow(global = new MotionGlobal(plugin,
-               this,
-               x1,
-               y));
+//     add_subwindow(global = new MotionGlobal(plugin,
+//             this,
+//             x1,
+//             y));
 
        add_subwindow(rotate = new MotionRotate(plugin,
                this,
@@ -108,20 +108,20 @@ void MotionWindow::create_objects()
 //             y,
 //             &plugin->config.rotation_block_h));
 
-       y += 50;
-       add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
-       add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
-               x1 + title->get_w() + 10,
-               y,
-               80));
-       global_search_positions->create_objects();
-
-       add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
-       add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
-               x2 + title->get_w() + 10,
-               y,
-               80));
-       rotation_search_positions->create_objects();
+//     y += 50;
+//     add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
+//     add_subwindow(global_search_positions = new GlobalSearchPositions(plugin, 
+//             x1 + title->get_w() + 10, 
+//             y, 
+//             80));
+//     global_search_positions->create_objects();
+// 
+//     add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
+//     add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin, 
+//             x2 + title->get_w() + 10, 
+//             y, 
+//             80));
+//     rotation_search_positions->create_objects();
 
        y += 50;
        add_subwindow(title = new BC_Title(x, y, _("Translation direction:")));
@@ -209,11 +209,6 @@ void MotionWindow::create_objects()
                this,
                x + track_single->get_w() + title->get_w() + 20,
                y));
-       add_subwindow(addtrackedframeoffset = new AddTrackedFrameOffset(plugin,
-               this,
-               x + track_single->get_w() + title->get_w() + 20 + track_frame_number->get_w(),
-               y));
-
 
        y += 20;
        add_subwindow(track_previous = new TrackPreviousFrame(plugin,
@@ -273,9 +268,8 @@ void MotionWindow::update_mode()
                MIN_ROTATION,
                MAX_ROTATION);
        vectors->update(plugin->config.draw_vectors);
-       global->update(plugin->config.global);
+//     global->update(plugin->config.global);
        rotate->update(plugin->config.rotate);
-       addtrackedframeoffset->update(plugin->config.addtrackedframeoffset);
 }
 
 
@@ -397,81 +391,81 @@ int BlockSize::handle_event()
 
 
 
-GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin,
-       int x,
-       int y,
-       int w)
- : BC_PopupMenu(x,
-       y,
-       w,
-       "",
-       1)
-{
-       this->plugin = plugin;
-}
-void GlobalSearchPositions::create_objects()
-{
-       add_item(new BC_MenuItem("16"));
-       add_item(new BC_MenuItem("32"));
-       add_item(new BC_MenuItem("64"));
-       add_item(new BC_MenuItem("128"));
-       add_item(new BC_MenuItem("256"));
-       add_item(new BC_MenuItem("512"));
-       add_item(new BC_MenuItem("1024"));
-       add_item(new BC_MenuItem("2048"));
-       add_item(new BC_MenuItem("4096"));
-       add_item(new BC_MenuItem("8192"));
-       add_item(new BC_MenuItem("16384"));
-       add_item(new BC_MenuItem("32768"));
-       add_item(new BC_MenuItem("65536"));
-       add_item(new BC_MenuItem("131072"));
-       char string[BCTEXTLEN];
-       sprintf(string, "%d", plugin->config.global_positions);
-       set_text(string);
-}
-
-int GlobalSearchPositions::handle_event()
-{
-       plugin->config.global_positions = atoi(get_text());
-       plugin->send_configure_change();
-       return 1;
-}
-
-
-
-
-
-
-
-RotationSearchPositions::RotationSearchPositions(MotionMain *plugin,
-       int x,
-       int y,
-       int w)
- : BC_PopupMenu(x,
-       y,
-       w,
-       "",
-       1)
-{
-       this->plugin = plugin;
-}
-void RotationSearchPositions::create_objects()
-{
-       add_item(new BC_MenuItem("4"));
-       add_item(new BC_MenuItem("8"));
-       add_item(new BC_MenuItem("16"));
-       add_item(new BC_MenuItem("32"));
-       char string[BCTEXTLEN];
-       sprintf(string, "%d", plugin->config.rotate_positions);
-       set_text(string);
-}
-
-int RotationSearchPositions::handle_event()
-{
-       plugin->config.rotate_positions = atoi(get_text());
-       plugin->send_configure_change();
-       return 1;
-}
+// GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin, 
+//     int x, 
+//     int y,
+//     int w)
+//  : BC_PopupMenu(x,
+//     y,
+//     w,
+//     "",
+//     1)
+// {
+//     this->plugin = plugin;
+// }
+// void GlobalSearchPositions::create_objects()
+// {
+//     add_item(new BC_MenuItem("16"));
+//     add_item(new BC_MenuItem("32"));
+//     add_item(new BC_MenuItem("64"));
+//     add_item(new BC_MenuItem("128"));
+//     add_item(new BC_MenuItem("256"));
+//     add_item(new BC_MenuItem("512"));
+//     add_item(new BC_MenuItem("1024"));
+//     add_item(new BC_MenuItem("2048"));
+//     add_item(new BC_MenuItem("4096"));
+//     add_item(new BC_MenuItem("8192"));
+//     add_item(new BC_MenuItem("16384"));
+//     add_item(new BC_MenuItem("32768"));
+//     add_item(new BC_MenuItem("65536"));
+//     add_item(new BC_MenuItem("131072"));
+//     char string[BCTEXTLEN];
+//     sprintf(string, "%d", plugin->config.global_positions);
+//     set_text(string);
+// }
+// 
+// int GlobalSearchPositions::handle_event()
+// {
+//     plugin->config.global_positions = atoi(get_text());
+//     plugin->send_configure_change();
+//     return 1;
+// }
+// 
+// 
+// 
+// 
+// 
+// 
+// 
+// RotationSearchPositions::RotationSearchPositions(MotionMain *plugin, 
+//     int x, 
+//     int y,
+//     int w)
+//  : BC_PopupMenu(x,
+//     y,
+//     w,
+//     "",
+//     1)
+// {
+//     this->plugin = plugin;
+// }
+// void RotationSearchPositions::create_objects()
+// {
+//     add_item(new BC_MenuItem("4"));
+//     add_item(new BC_MenuItem("8"));
+//     add_item(new BC_MenuItem("16"));
+//     add_item(new BC_MenuItem("32"));
+//     char string[BCTEXTLEN];
+//     sprintf(string, "%d", plugin->config.rotate_positions);
+//     set_text(string);
+// }
+// 
+// int RotationSearchPositions::handle_event()
+// {
+//     plugin->config.rotate_positions = atoi(get_text());
+//     plugin->send_configure_change();
+//     return 1;
+// }
 
 
 
@@ -521,27 +515,6 @@ int MotionReturnSpeed::handle_event()
 
 
 
-AddTrackedFrameOffset::AddTrackedFrameOffset(MotionMain *plugin,
-       MotionWindow *gui,
-       int x,
-       int y)
- : BC_CheckBox(x,
-       y,
-       plugin->config.addtrackedframeoffset,
-       _("Add (loaded) offset from tracked frame"))
-{
-       this->plugin = plugin;
-       this->gui = gui;
-}
-
-int AddTrackedFrameOffset::handle_event()
-{
-       plugin->config.addtrackedframeoffset = get_value();
-       plugin->send_configure_change();
-       return 1;
-}
-
-
 MotionRMagnitude::MotionRMagnitude(MotionMain *plugin,
        int x,
        int y)
@@ -586,25 +559,25 @@ int MotionRReturnSpeed::handle_event()
 
 
 
-MotionGlobal::MotionGlobal(MotionMain *plugin,
-       MotionWindow *gui,
-       int x,
-       int y)
- : BC_CheckBox(x,
-       y,
-       plugin->config.global,
-       _("Track translation"))
-{
-       this->plugin = plugin;
-       this->gui = gui;
-}
-
-int MotionGlobal::handle_event()
-{
-       plugin->config.global = get_value();
-       plugin->send_configure_change();
-       return 1;
-}
+// MotionGlobal::MotionGlobal(MotionMain *plugin, 
+//     MotionWindow *gui,
+//     int x, 
+//     int y)
+//  : BC_CheckBox(x, 
+//     y, 
+//     plugin->config.global,
+//     _("Track translation"))
+// {
+//     this->plugin = plugin;
+//     this->gui = gui;
+// }
+// 
+// int MotionGlobal::handle_event()
+// {
+//     plugin->config.global = get_value();
+//     plugin->send_configure_change();
+//     return 1;
+// }
 
 MotionRotate::MotionRotate(MotionMain *plugin,
        MotionWindow *gui,
index 4a66a1a6cbdee42e364f1f0f1a1985070b619bce..c52914e45bbae1fa29f4ffec2e2ae9c85f081136 100644 (file)
@@ -215,29 +215,29 @@ public:
        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
 {
@@ -305,17 +305,17 @@ public:
        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
 {
@@ -353,15 +353,15 @@ public:
        MotionBlockY *block_y;
        MotionBlockXText *block_x_text;
        MotionBlockYText *block_y_text;
-       GlobalSearchPositions *global_search_positions;
-       RotationSearchPositions *rotation_search_positions;
+//     GlobalSearchPositions *global_search_positions;
+//     RotationSearchPositions *rotation_search_positions;
        MotionMagnitude *magnitude;
        MotionRMagnitude *rotate_magnitude;
        MotionReturnSpeed *return_speed;
        MotionRReturnSpeed *rotate_return_speed;
        ActionType *action_type;
        MotionDrawVectors *vectors;
-       MotionGlobal *global;
+//     MotionGlobal *global;
        MotionRotate *rotate;
        AddTrackedFrameOffset *addtrackedframeoffset;
        TrackSingleFrame *track_single;
diff --git a/cinelerra-5.1/plugins/motion/rotatescan.C b/cinelerra-5.1/plugins/motion/rotatescan.C
new file mode 100644 (file)
index 0000000..e7b346e
--- /dev/null
@@ -0,0 +1,471 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "affine.h"
+#include "bcsignals.h"
+#include "clip.h"
+#include "motionscan.h"
+#include "rotatescan.h"
+#include "motion.h"
+#include "mutex.h"
+#include "vframe.h"
+
+
+
+
+
+
+
+
+
+RotateScanPackage::RotateScanPackage()
+{
+}
+
+
+RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
+ : LoadClient(server)
+{
+       this->server = server;
+       this->plugin = plugin;
+       rotater = 0;
+       temp = 0;
+}
+
+RotateScanUnit::~RotateScanUnit()
+{
+       delete rotater;
+       delete temp;
+}
+
+void RotateScanUnit::process_package(LoadPackage *package)
+{
+       if(server->skip) return;
+       RotateScanPackage *pkg = (RotateScanPackage*)package;
+
+       if((pkg->difference = server->get_cache(pkg->angle)) < 0)
+       {
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+               int color_model = server->previous_frame->get_color_model();
+               int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+               int row_bytes = server->previous_frame->get_bytes_per_line();
+
+               if(!rotater)
+                       rotater = new AffineEngine(1, 1);
+               if(!temp) temp = new VFrame(0,
+                       -1,
+                       server->previous_frame->get_w(),
+                       server->previous_frame->get_h(),
+                       color_model,
+                       -1);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+
+
+// Rotate original block size
+//             rotater->set_viewport(server->block_x1,
+//                     server->block_y1,
+//                     server->block_x2 - server->block_x1,
+//                     server->block_y2 - server->block_y1);
+               rotater->set_in_viewport(server->block_x1,
+                       server->block_y1,
+                       server->block_x2 - server->block_x1,
+                       server->block_y2 - server->block_y1);
+               rotater->set_out_viewport(server->block_x1,
+                       server->block_y1,
+                       server->block_x2 - server->block_x1,
+                       server->block_y2 - server->block_y1);
+//             rotater->set_pivot(server->block_x, server->block_y);
+               rotater->set_in_pivot(server->block_x, server->block_y);
+               rotater->set_out_pivot(server->block_x, server->block_y);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+               rotater->rotate(temp,
+                       server->previous_frame,
+                       pkg->angle);
+
+// Scan reduced block size
+//plugin->output_frame->copy_from(server->current_frame);
+//plugin->output_frame->copy_from(temp);
+// printf("RotateScanUnit::process_package %d %d %d %d %d\n",
+// __LINE__,
+// server->scan_x,
+// server->scan_y,
+// server->scan_w,
+// server->scan_h);
+// Clamp coordinates
+               int x1 = server->scan_x;
+               int y1 = server->scan_y;
+               int x2 = x1 + server->scan_w;
+               int y2 = y1 + server->scan_h;
+               x2 = MIN(temp->get_w(), x2);
+               y2 = MIN(temp->get_h(), y2);
+               x2 = MIN(server->current_frame->get_w(), x2);
+               y2 = MIN(server->current_frame->get_h(), y2);
+               x1 = MAX(0, x1);
+               y1 = MAX(0, y1);
+
+               if(x2 > x1 && y2 > y1)
+               {
+                       pkg->difference = MotionScan::abs_diff(
+                               temp->get_rows()[y1] + x1 * pixel_size,
+                               server->current_frame->get_rows()[y1] + x1 * pixel_size,
+                               row_bytes,
+                               x2 - x1,
+                               y2 - y1,
+                               color_model);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+                       server->put_cache(pkg->angle, pkg->difference);
+               }
+
+// printf("RotateScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%lld\n",
+// server->block_x1,
+// server->block_y1,
+// server->block_x2 - server->block_x1,
+// server->block_y2 - server->block_y1,
+// server->block_x,
+// server->block_y,
+// pkg->angle,
+// server->scan_w,
+// server->scan_h,
+// pkg->difference);
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+RotateScan::RotateScan(MotionMain *plugin,
+       int total_clients,
+       int total_packages)
+ : LoadServer(
+//1, 1
+total_clients, total_packages
+)
+{
+       this->plugin = plugin;
+       cache_lock = new Mutex("RotateScan::cache_lock");
+}
+
+
+RotateScan::~RotateScan()
+{
+       delete cache_lock;
+}
+
+void RotateScan::init_packages()
+{
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
+               pkg->angle = i *
+                       (scan_angle2 - scan_angle1) /
+                       (total_steps - 1) +
+                       scan_angle1;
+       }
+}
+
+LoadClient* RotateScan::new_client()
+{
+       return new RotateScanUnit(this, plugin);
+}
+
+LoadPackage* RotateScan::new_package()
+{
+       return new RotateScanPackage;
+}
+
+
+float RotateScan::scan_frame(VFrame *previous_frame,
+       VFrame *current_frame,
+       int block_x,
+       int block_y)
+{
+       skip = 0;
+       this->block_x = block_x;
+       this->block_y = block_y;
+
+//printf("RotateScan::scan_frame %d\n", __LINE__);
+       switch(plugin->config.tracking_type)
+       {
+               case MotionScan::NO_CALCULATE:
+                       result = plugin->config.rotation_center;
+                       skip = 1;
+                       break;
+
+               case MotionScan::LOAD:
+               {
+                       char string[BCTEXTLEN];
+                       sprintf(string,
+                               "%s%06ld",
+                               ROTATION_FILE,
+                               plugin->get_source_position());
+                       FILE *input = fopen(string, "r");
+                       if(input)
+                       {
+                               int temp = fscanf(input, "%f", &result);
+                               fclose(input);
+                               skip = 1;
+                       }
+                       else
+                       {
+                               perror("RotateScan::scan_frame LOAD");
+                       }
+                       break;
+               }
+       }
+
+
+
+
+
+
+
+
+       this->previous_frame = previous_frame;
+       this->current_frame = current_frame;
+       int w = current_frame->get_w();
+       int h = current_frame->get_h();
+       int block_w = w * plugin->config.global_block_w / 100;
+       int block_h = h * plugin->config.global_block_h / 100;
+
+       if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
+       if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
+       if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
+       if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
+
+       block_x1 = this->block_x - block_w / 2;
+       block_x2 = this->block_x + block_w / 2;
+       block_y1 = this->block_y - block_h / 2;
+       block_y2 = this->block_y + block_h / 2;
+
+
+// Calculate the maximum area available to scan after rotation.
+// Must be calculated from the starting range because of cache.
+// Get coords of rectangle after rotation.
+       double center_x = this->block_x;
+       double center_y = this->block_y;
+       double max_angle = plugin->config.rotation_range;
+       double base_angle1 = atan((float)block_h / block_w);
+       double base_angle2 = atan((float)block_w / block_h);
+       double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
+       double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
+       double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
+       double x1 = center_x - cos(target_angle1) * radius;
+       double y1 = center_y - sin(target_angle1) * radius;
+       double x2 = center_x + sin(target_angle2) * radius;
+       double y2 = center_y - cos(target_angle2) * radius;
+       double x3 = center_x - sin(target_angle2) * radius;
+       double y3 = center_y + cos(target_angle2) * radius;
+
+// Track top edge to find greatest area.
+       double max_area1 = 0;
+       double max_x1 = 0;
+       double max_y1 = 0;
+       for(double x = x1; x < x2; x++)
+       {
+               double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+               if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area1)
+                       {
+                               max_area1 = area;
+                               max_x1 = x;
+                               max_y1 = y;
+                       }
+               }
+       }
+
+// Track left edge to find greatest area.
+       double max_area2 = 0;
+       double max_x2 = 0;
+       double max_y2 = 0;
+       for(double y = y1; y < y3; y++)
+       {
+               double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
+               if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
+               {
+                       double area = fabs(x - center_x) * fabs(y - center_y);
+                       if(area > max_area2)
+                       {
+                               max_area2 = area;
+                               max_x2 = x;
+                               max_y2 = y;
+                       }
+               }
+       }
+
+       double max_x, max_y;
+       max_x = max_x2;
+       max_y = max_y1;
+
+// Get reduced scan coords
+       scan_w = (int)(fabs(max_x - center_x) * 2);
+       scan_h = (int)(fabs(max_y - center_y) * 2);
+       scan_x = (int)(center_x - scan_w / 2);
+       scan_y = (int)(center_y - scan_h / 2);
+// printf("RotateScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n",
+// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
+// printf("    angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
+
+// Determine min angle from size of block
+       double angle1 = atan((double)block_h / block_w);
+       double angle2 = atan((double)(block_h - 1) / (block_w + 1));
+       double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
+       min_angle = MAX(min_angle, MIN_ANGLE);
+
+//printf("RotateScan::scan_frame %d min_angle=%f\n", __LINE__, min_angle * 360 / 2 / M_PI);
+
+       cache.remove_all_objects();
+
+
+       if(!skip)
+       {
+               if(previous_frame->data_matches(current_frame))
+               {
+//printf("RotateScan::scan_frame: frames match.  Skipping.\n");
+                       result = plugin->config.rotation_center;
+                       skip = 1;
+               }
+       }
+
+       if(!skip)
+       {
+// Initial search range
+               float angle_range = max_angle;
+               result = plugin->config.rotation_center;
+               total_steps = plugin->config.rotate_positions;
+
+
+               while(angle_range >= min_angle * total_steps)
+               {
+                       scan_angle1 = result - angle_range;
+                       scan_angle2 = result + angle_range;
+
+
+                       set_package_count(total_steps);
+//set_package_count(1);
+                       process_packages();
+
+                       int64_t min_difference = -1;
+                       for(int i = 0; i < get_total_packages(); i++)
+                       {
+                               RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
+                               if(pkg->difference < min_difference || min_difference == -1)
+                               {
+                                       min_difference = pkg->difference;
+                                       result = pkg->angle;
+                               }
+//break;
+                       }
+
+                       angle_range /= 2;
+
+//break;
+               }
+       }
+
+//printf("RotateScan::scan_frame %d\n", __LINE__);
+
+       if(!skip && plugin->config.tracking_type == MotionScan::SAVE)
+       {
+               char string[BCTEXTLEN];
+               sprintf(string,
+                       "%s%06ld",
+                       ROTATION_FILE,
+                       plugin->get_source_position());
+               FILE *output = fopen(string, "w");
+               if(output)
+               {
+                       fprintf(output, "%f\n", result);
+                       fclose(output);
+               }
+               else
+               {
+                       perror("RotateScan::scan_frame SAVE");
+               }
+       }
+
+//printf("RotateScan::scan_frame %d angle=%f\n", __LINE__, result);
+
+
+
+       return result;
+}
+
+int64_t RotateScan::get_cache(float angle)
+{
+       int64_t result = -1;
+       cache_lock->lock("RotateScan::get_cache");
+       for(int i = 0; i < cache.total; i++)
+       {
+               RotateScanCache *ptr = cache.values[i];
+               if(fabs(ptr->angle - angle) <= MIN_ANGLE)
+               {
+                       result = ptr->difference;
+                       break;
+               }
+       }
+       cache_lock->unlock();
+       return result;
+}
+
+void RotateScan::put_cache(float angle, int64_t difference)
+{
+       RotateScanCache *ptr = new RotateScanCache(angle, difference);
+       cache_lock->lock("RotateScan::put_cache");
+       cache.append(ptr);
+       cache_lock->unlock();
+}
+
+
+
+
+
+
+
+
+
+RotateScanCache::RotateScanCache(float angle, int64_t difference)
+{
+       this->angle = angle;
+       this->difference = difference;
+}
+
+
+
diff --git a/cinelerra-5.1/plugins/motion/rotatescan.h b/cinelerra-5.1/plugins/motion/rotatescan.h
new file mode 100644 (file)
index 0000000..27001e3
--- /dev/null
@@ -0,0 +1,136 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+
+
+#ifndef ROTATESCAN_H
+#define ROTATESCAN_H
+
+
+
+#include "affine.inc"
+#include "loadbalance.h"
+#include "motion.inc"
+#include "vframe.inc"
+#include <stdint.h>
+
+class RotateScan;
+
+
+class RotateScanPackage : public LoadPackage
+{
+public:
+       RotateScanPackage();
+       float angle;
+       int64_t difference;
+};
+
+class RotateScanCache
+{
+public:
+       RotateScanCache(float angle, int64_t difference);
+       float angle;
+       int64_t difference;
+};
+
+class RotateScanUnit : public LoadClient
+{
+public:
+       RotateScanUnit(RotateScan *server, MotionMain *plugin);
+       ~RotateScanUnit();
+
+       void process_package(LoadPackage *package);
+
+       RotateScan *server;
+       MotionMain *plugin;
+       AffineEngine *rotater;
+       VFrame *temp;
+};
+
+class RotateScan : public LoadServer
+{
+public:
+       RotateScan(MotionMain *plugin,
+               int total_clients,
+               int total_packages);
+       ~RotateScan();
+
+       friend class RotateScanUnit;
+
+       void init_packages();
+       LoadClient* new_client();
+       LoadPackage* new_package();
+
+// Invoke the motion engine for a search
+// Frame before rotation
+       float scan_frame(VFrame *previous_frame,
+// Frame after rotation
+               VFrame *current_frame,
+// Pivot
+               int block_x,
+               int block_y);
+       int64_t get_cache(float angle);
+       void put_cache(float angle, int64_t difference);
+
+
+// Angle result
+       float result;
+
+private:
+       VFrame *previous_frame;
+// Frame after motion
+       VFrame *current_frame;
+
+       MotionMain *plugin;
+       int skip;
+
+// Pivot
+       int block_x;
+       int block_y;
+// Block to rotate
+       int block_x1;
+       int block_x2;
+       int block_y1;
+       int block_y2;
+// Area to compare
+       int scan_x;
+       int scan_y;
+       int scan_w;
+       int scan_h;
+// Range of angles to compare
+       float scan_angle1, scan_angle2;
+       int total_steps;
+
+       ArrayList<RotateScanCache*> cache;
+       Mutex *cache_lock;
+};
+
+
+
+
+
+#endif
+
+
+
+
+
diff --git a/cinelerra-5.1/plugins/motion/rotatescan.inc b/cinelerra-5.1/plugins/motion/rotatescan.inc
new file mode 100644 (file)
index 0000000..d3dfd97
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef ROTATESCAN_INC
+#define ROTATESCAN_INC
+
+
+class RotateScan;
+
+
+#endif
+
+
+
+
index 4130e2d811c2126f7b0f9b1735d5b96a6f247f10..3b6c955af053c755bf701f099f7411e465d904c4 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -445,34 +445,37 @@ void MotionMain2::allocate_temp(int w, int h, int color_model)
 
 void MotionMain2::scan_motion(int point)
 {
+       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);
 
 // Get the current motion vector between the previous and current frame
        engine->scan_frame(current_global_ref, 
                prev_global_ref, 
-               config.global_range_w[point],
-               config.global_range_h[point],
-               config.global_block_w[point],
-               config.global_block_h[point],
-               config.block_x[point],
-               config.block_y[point],
+               config.global_range_w[point] * w / 100,
+               config.global_range_h[point] * h / 100,
+               config.global_block_w[point] * w / 100,
+               config.global_block_h[point] * h / 100,
+               config.block_x[point] * w / 100,
+               config.block_y[point] * h / 100,
                config.tracking_object,
                config.calculation,
                config.action,
                config.horizontal_only,
                config.vertical_only,
                get_source_position(),
-               config.global_positions,
                total_dx[point],
                total_dy[point],
-               config.global_origin_x[point],
-               config.global_origin_y[point]);
+               config.global_origin_x[point] * w / 100,
+               config.global_origin_y[point] * h / 100,
+               1,
+               0,
+               0,
+               0);
 
-//             0,
-//             0,
-//             0,
-//             0);
        current_dx[point] = engine->dx_result;
        current_dy[point] = engine->dy_result;
 
index d79e63a82a87c43b866bb000a17f37875bed7ad6..dd7ca7e14f2d08dd798c0e77dad905d61e116634 100644 (file)
@@ -1,8 +1,8 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
+ * Copyright (C) 2008-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
@@ -46,17 +46,30 @@ public:
                int64_t prev_frame,
                int64_t next_frame,
                int64_t current_frame);
-       double scale;
+// was scale
+       double num;
+       double denom;
        int stretch;
        int interp;
        int optic_flow;
 };
 
 
-class ReframeRTScale : public BC_TumbleTextBox
+class ReframeRTNum : public BC_TumbleTextBox
+{
+public:
+       ReframeRTNum(ReframeRT *plugin,
+               ReframeRTWindow *gui,
+               int x,
+               int y);
+       int handle_event();
+       ReframeRT *plugin;
+};
+
+class ReframeRTDenom : public BC_TumbleTextBox
 {
 public:
-       ReframeRTScale(ReframeRT *plugin,
+       ReframeRTDenom(ReframeRT *plugin,
                ReframeRTWindow *gui,
                int x,
                int y);
@@ -107,7 +120,8 @@ public:
        ~ReframeRTWindow();
        void create_objects();
        ReframeRT *plugin;
-       ReframeRTScale *scale;
+       ReframeRTNum *num;
+       ReframeRTDenom *denom;
        ReframeRTStretch *stretch;
        ReframeRTDownsample *downsample;
        ReframeRTInterpolate *interpolate;
@@ -144,7 +158,8 @@ REGISTER_PLUGIN(ReframeRT);
 
 ReframeRTConfig::ReframeRTConfig()
 {
-       scale = 1.0;
+       num = 1.0;
+       denom = 1.0;
        stretch = 0;
        interp = 0;
        optic_flow = 1;
@@ -152,14 +167,16 @@ ReframeRTConfig::ReframeRTConfig()
 
 int ReframeRTConfig::equivalent(ReframeRTConfig &src)
 {
-       return fabs(scale - src.scale) < 0.0001 &&
+       return fabs(num - src.num) < 0.0001 &&
+               fabs(denom - src.denom) < 0.0001 &&
                stretch == src.stretch &&
                interp == src.interp;
 }
 
 void ReframeRTConfig::copy_from(ReframeRTConfig &src)
 {
-       this->scale = src.scale;
+       this->num = src.num;
+       this->denom = src.denom;
        this->stretch = src.stretch;
        this->interp = src.interp;
 }
@@ -172,22 +189,27 @@ void ReframeRTConfig::interpolate(ReframeRTConfig &prev,
 {
        this->interp = prev.interp;
        this->stretch = prev.stretch;
+       this->denom = prev.denom;
 
        if (this->interp && prev_frame != next_frame)
        {
+               double next_weight = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
+               double prev_weight = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+               double prev_slope = prev.num / prev.denom, next_slope = next.num / next.denom;
                // for interpolation, this is (for now) a simple linear slope to the next keyframe.
-               double slope = (next.scale - prev.scale) / (next_frame - prev_frame);
-               this->scale = (slope * (current_frame - prev_frame)) + prev.scale;
+               double scale = prev_slope * prev_weight + next_slope * next_weight;
+               this->num = this->denom * scale;
        }
        else
        {
-               this->scale = prev.scale;
+               this->num = prev.num;
        }
 }
 
 void ReframeRTConfig::boundaries()
 {
-       if(fabs(scale) < 0.0001) scale = 0.0001;
+       if(num < 0.0001) num = 0.0001;
+       if(denom < 0.0001) denom = 0.0001;
 }
 
 
@@ -198,7 +220,7 @@ void ReframeRTConfig::boundaries()
 
 
 ReframeRTWindow::ReframeRTWindow(ReframeRT *plugin)
- : PluginClientWindow(plugin, 230, 160, 230, 160, 0)
+ : PluginClientWindow(plugin, 230, 190, 230, 190, 0)
 {
        this->plugin = plugin;
 }
@@ -209,33 +231,40 @@ ReframeRTWindow::~ReframeRTWindow()
 
 void ReframeRTWindow::create_objects()
 {
-       int x = 10, y = 10;
+       int x = plugin->get_theme()->window_border;
+       int y = plugin->get_theme()->window_border;
        BC_Title *title;
-       add_subwindow(title = new BC_Title(x, y, _("Scale by amount:")));
+       add_subwindow(title = new BC_Title(x, y, _("Input frames:")));
        y += title->get_h() + plugin->get_theme()->widget_border;
-       scale = new ReframeRTScale(plugin,
+       num = new ReframeRTNum(plugin, 
                this,
-               x,
+               x, 
                y);
-       scale->create_objects();
-       scale->set_increment(0.1);
-       y += 30;
-       add_subwindow(stretch = new ReframeRTStretch(plugin,
+       num->create_objects();
+       num->set_increment(1.0);
+
+       y += num->get_h() + plugin->get_theme()->widget_border;
+       add_subwindow(title = new BC_Title(x, y, _("Output frames:")));
+       y += title->get_h() + plugin->get_theme()->widget_border;
+       denom = new ReframeRTDenom(plugin, 
                this,
-               x,
-               y));
+               x, 
+               y);
+       denom->create_objects();
+       denom->set_increment(1.0);
+       
+       
+       y += denom->get_h() + plugin->get_theme()->widget_border;
+       add_subwindow(stretch = new ReframeRTStretch(plugin, this, x, y));
        y += 30;
-       add_subwindow(downsample = new ReframeRTDownsample(plugin,
-               this,
-               x,
-               y));
+       add_subwindow(downsample = new ReframeRTDownsample(plugin, this, x, y));
        y += 30;
-       add_subwindow(interpolate = new ReframeRTInterpolate(plugin,
-               this,
-               x,
-               y));
+       add_subwindow(interpolate = new ReframeRTInterpolate(plugin, this, x, y));
+       y += 30;
+       add_subwindow(stretch = new ReframeRTStretch(plugin, this, x, y));
+       y += stretch->get_h() + plugin->get_theme()->widget_border;
+       add_subwindow(downsample = new ReframeRTDownsample(plugin, this, x, y));
        show_window();
-       flush();
 }
 
 
@@ -245,29 +274,54 @@ void ReframeRTWindow::create_objects()
 
 
 
-ReframeRTScale::ReframeRTScale(ReframeRT *plugin,
+ReframeRTNum::ReframeRTNum(ReframeRT *plugin, 
        ReframeRTWindow *gui,
-       int x,
+       int x, 
        int y)
  : BC_TumbleTextBox(gui,
-       (float)plugin->config.scale,
+       (float)plugin->config.num,
+       (float)0.0001,
+       (float)1000,
+       x, 
+       y, 
+       gui->get_w() - plugin->get_theme()->window_border * 3)
+{
+       this->plugin = plugin;
+}
+
+int ReframeRTNum::handle_event()
+{
+       plugin->config.num = atof(get_text());
+       plugin->config.boundaries();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+ReframeRTDenom::ReframeRTDenom(ReframeRT *plugin, 
+       ReframeRTWindow *gui,
+       int x, 
+       int y)
+ : BC_TumbleTextBox(gui,
+       (float)plugin->config.denom,
        (float)-1000,
        (float)1000,
        x,
        y,
-       100)
+       gui->get_w() - plugin->get_theme()->window_border * 3)
 {
        this->plugin = plugin;
 }
 
-int ReframeRTScale::handle_event()
+int ReframeRTDenom::handle_event()
 {
-       plugin->config.scale = atof(get_text());
+       plugin->config.denom = atof(get_text());
        plugin->config.boundaries();
        plugin->send_configure_change();
        return 1;
 }
 
+
 ReframeRTStretch::ReframeRTStretch(ReframeRT *plugin,
        ReframeRTWindow *gui,
        int x,
@@ -389,12 +443,17 @@ int ReframeRT::process_buffer(VFrame *frame,
                // the area under the curve is the number of frames to advance
                // as long as interpolate() uses a linear slope we can use geometry to determine this
                // if interpolate() changes to use a curve then this needs use (possibly) the definite integral
-               input_frame += (int64_t)(segment_len * ((prev_config.scale + config.scale) / 2));
+               double prev_scale = prev_config.num / prev_config.denom;
+               double config_scale = config.num / config.denom;
+               input_frame += (int64_t)(segment_len * ((prev_scale + config_scale) / 2));
        } while (!is_current_keyframe);
 
 // Change rate
        if (!config.stretch)
-               input_rate *= config.scale;
+       {
+               input_rate *= config.num / config.denom;
+
+       }
 
 // printf("ReframeRT::process_buffer %d %lld %f %lld %f\n",
 // __LINE__,
@@ -423,7 +482,9 @@ void ReframeRT::save_data(KeyFrame *keyframe)
 // cause data to be stored directly in text
        output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
        output.tag.set_title("REFRAMERT");
-       output.tag.set_property("SCALE", config.scale);
+// for backwards compatability, we call num scale
+       output.tag.set_property("SCALE", config.num);
+       output.tag.set_property("DENOM", config.denom);
        output.tag.set_property("STRETCH", config.stretch);
        output.tag.set_property("INTERPOLATE", config.interp);
        output.append_tag();
@@ -443,7 +504,9 @@ void ReframeRT::read_data(KeyFrame *keyframe)
        {
                if(input.tag.title_is("REFRAMERT"))
                {
-                       config.scale = input.tag.get_property("SCALE", config.scale);
+// for backwards compatability, we call num scale
+                       config.num = input.tag.get_property("SCALE", config.num);
+                       config.denom = input.tag.get_property("DENOM", config.denom);
                        config.stretch = input.tag.get_property("STRETCH", config.stretch);
                        config.interp = input.tag.get_property("INTERPOLATE", config.interp);
                }
@@ -460,7 +523,8 @@ void ReframeRT::update_gui()
                {
                        ReframeRTWindow* window = (ReframeRTWindow*)thread->window;
                        window->lock_window("ReframeRT::update_gui");
-                       window->scale->update((float)config.scale);
+                       window->num->update((float)config.num);
+                       window->denom->update((float)config.denom);
                        window->stretch->update(config.stretch);
                        window->downsample->update(!config.stretch);
                        window->interpolate->update(config.interp);
index e6de8c3479548ddbbbfaa15c946c9c8e744c97a3..bde3bbc6efcb005699eeac2a449c7668f9c636bf 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2010-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
@@ -41,18 +41,21 @@ REGISTER_PLUGIN(ResampleRT);
 
 ResampleRTConfig::ResampleRTConfig()
 {
-       scale = 1;
+       num = 1;
+       denom = 1;
 }
 
 
 int ResampleRTConfig::equivalent(ResampleRTConfig &src)
 {
-       return fabs(scale - src.scale) < 0.0001;
+       return fabs(num - src.num) < 0.0001 &&
+               fabs(denom - src.denom) < 0.0001;
 }
 
 void ResampleRTConfig::copy_from(ResampleRTConfig &src)
 {
-       this->scale = src.scale;
+       this->num = src.num;
+       this->denom = src.denom;
 }
 
 void ResampleRTConfig::interpolate(ResampleRTConfig &prev, 
@@ -61,12 +64,14 @@ void ResampleRTConfig::interpolate(ResampleRTConfig &prev,
        int64_t next_frame, 
        int64_t current_frame)
 {
-       this->scale = prev.scale;
+       this->num = prev.num;
+       this->denom = prev.denom;
 }
 
 void ResampleRTConfig::boundaries()
 {
-       if(fabs(scale) < 0.0001) scale = 0.0001;
+       if(num < 0.0001) num = 0.0001;
+       if(denom < 0.0001) denom = 0.0001;
 }
 
 
@@ -89,17 +94,21 @@ ResampleRTWindow::~ResampleRTWindow()
 
 void ResampleRTWindow::create_objects()
 {
-       int x = 10, y = 10;
+       int x = plugin->get_theme()->window_border;
+       int y = plugin->get_theme()->window_border;
 
        BC_Title *title;
-       add_subwindow(title = new BC_Title(x, y, _("Scale by amount:")));
+       add_subwindow(title = new BC_Title(x, y, _("Input samples:")));
        y += title->get_h() + plugin->get_theme()->widget_border;
-
-       scale = new ResampleRTScale(this,
-               plugin, 
-               x, 
-               y);
-       scale->create_objects();
+       num = new ResampleRTNum(this, plugin, x, y);
+       num->create_objects();
+       
+       y += num->get_h() + plugin->get_theme()->widget_border;
+       add_subwindow(title = new BC_Title(x, y, _("Output samples:")));
+       y += title->get_h() + plugin->get_theme()->widget_border;
+       denom = new ResampleRTDenom(this, plugin, x, y);
+       denom->create_objects();
+       
        show_window();
 }
 
@@ -108,12 +117,39 @@ void ResampleRTWindow::create_objects()
 
 
 
-ResampleRTScale::ResampleRTScale(ResampleRTWindow *window,
+ResampleRTNum::ResampleRTNum(ResampleRTWindow *window,
+       ResampleRT *plugin, 
+       int x, 
+       int y)
+ : BC_TumbleTextBox(window,
+       plugin->config.num,
+       (float)0.0001,
+       (float)1000,
+       x, 
+       y, 
+       100)
+{
+       this->plugin = plugin;
+       set_increment(0.001);
+}
+
+int ResampleRTNum::handle_event()
+{
+       plugin->config.num = atof(get_text());
+       plugin->config.boundaries();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+ResampleRTDenom::ResampleRTDenom(ResampleRTWindow *window,
        ResampleRT *plugin, 
        int x, 
        int y)
  : BC_TumbleTextBox(window,
-       plugin->config.scale,
+       plugin->config.denom,
        (float)0.0001,
        (float)1000,
        x, 
@@ -124,9 +160,10 @@ ResampleRTScale::ResampleRTScale(ResampleRTWindow *window,
        set_increment(0.001);
 }
 
-int ResampleRTScale::handle_event()
+int ResampleRTDenom::handle_event()
 {
-       plugin->config.scale = atof(get_text());
+       plugin->config.denom = atof(get_text());
+       plugin->config.boundaries();
        plugin->send_configure_change();
        return 1;
 }
@@ -220,7 +257,7 @@ int ResampleRT::process_buffer(int64_t size,
                }
 
                source_start = (int64_t)((start_position - prev_position) * 
-                       config.scale) + prev_position;
+                       config.num / config.denom) + prev_position;
 
                resample->reset();
                need_reconfigure = 0;
@@ -228,8 +265,8 @@ int ResampleRT::process_buffer(int64_t size,
 
        resample->resample(buffer,
                size,
-               (int)1000000,
-               (int)(1000000 / config.scale),
+               (int)(65536 * config.num),
+               (int)(65536 * config.denom),
                start_position,
                get_direction());       
 
@@ -256,7 +293,8 @@ void ResampleRT::save_data(KeyFrame *keyframe)
 // cause data to be stored directly in text
        output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
        output.tag.set_title("RESAMPLERT");
-       output.tag.set_property("SCALE", config.scale);
+       output.tag.set_property("SCALE", config.num);
+       output.tag.set_property("DENOM", config.denom);
        output.append_tag();
        output.tag.set_title("/RESAMPLERT");
        output.append_tag();
@@ -274,7 +312,8 @@ void ResampleRT::read_data(KeyFrame *keyframe)
        {
                if(input.tag.title_is("RESAMPLERT"))
                {
-                       config.scale = input.tag.get_property("SCALE", config.scale);
+                       config.num = input.tag.get_property("SCALE", config.num);
+                       config.denom = input.tag.get_property("DENOM", config.denom);
                }
        }
 }
@@ -286,7 +325,8 @@ void ResampleRT::update_gui()
                if(load_configuration())
                {
                        thread->window->lock_window("ResampleRT::update_gui");
-                       ((ResampleRTWindow*)thread->window)->scale->update((float)config.scale);
+                       ((ResampleRTWindow*)thread->window)->num->update((float)config.num);
+                       ((ResampleRTWindow*)thread->window)->denom->update((float)config.denom);
                        thread->window->unlock_window();
                }
        }
index 8d7300ffa99cbd5eeed97cd58a3f553a829ed063..a9f6f2dbfba1e28111e17ba1ab3ec9df8c65da6e 100644 (file)
@@ -44,14 +44,27 @@ public:
                int64_t prev_frame, 
                int64_t next_frame, 
                int64_t current_frame);
-       double scale;
+// was scale
+       double num;
+       double denom;
 };
 
 
-class ResampleRTScale : public BC_TumbleTextBox
+class ResampleRTNum : public BC_TumbleTextBox
 {
 public:
-       ResampleRTScale(ResampleRTWindow *window,
+       ResampleRTNum(ResampleRTWindow *window,
+               ResampleRT *plugin,
+               int x,
+               int y);
+       int handle_event();
+       ResampleRT *plugin;
+};
+
+class ResampleRTDenom : public BC_TumbleTextBox
+{
+public:
+       ResampleRTDenom(ResampleRTWindow *window,
                ResampleRT *plugin,
                int x,
                int y);
@@ -67,7 +80,8 @@ public:
        void create_objects();
 
        ResampleRT *plugin;
-       ResampleRTScale *scale;
+       ResampleRTNum *num;
+       ResampleRTDenom *denom;
 };
 
 
index 0ebeb60d92bdc887937f525f005d4e18d2f3ee56..e97334e10603b1997d06d8e591e920a19f75045f 100644 (file)
@@ -741,7 +741,7 @@ int RotateEffect::process_buffer(VFrame *frame,
                temp_frame, 
                config.angle);
 
-//printf("RotateEffect::process_buffer %d\n", __LINE__);
+//printf("RotateEffect::process_buffer %d draw_pivot=%d\n", __LINE__, config.draw_pivot);
 
 // Draw center
 #define CENTER_H 20