From: Good Guy Date: Tue, 15 Nov 2016 19:28:25 +0000 (-0700) Subject: merge hv v6, rework trace methods X-Git-Url: https://cinelerra-gg.org/git/?a=commitdiff_plain;h=5a1b2bb96f2bd6b7ef4f8031763683726c02219d;p=goodguy%2Fhistory.git merge hv v6, rework trace methods --- diff --git a/cinelerra-5.1/cinelerra/affine.C b/cinelerra-5.1/cinelerra/affine.C index 32f630fc..f6bedb2e 100644 --- a/cinelerra-5.1/cinelerra/affine.C +++ b/cinelerra-5.1/cinelerra/affine.C @@ -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) diff --git a/cinelerra-5.1/cinelerra/affine.h b/cinelerra-5.1/cinelerra/affine.h index 46119e2b..d03f6cd8 100644 --- a/cinelerra-5.1/cinelerra/affine.h +++ b/cinelerra-5.1/cinelerra/affine.h @@ -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; }; diff --git a/cinelerra-5.1/cinelerra/assetedit.C b/cinelerra-5.1/cinelerra/assetedit.C index 7854999d..0b77d919 100644 --- a/cinelerra-5.1/cinelerra/assetedit.C +++ b/cinelerra-5.1/cinelerra/assetedit.C @@ -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; diff --git a/cinelerra-5.1/cinelerra/assetpopup.C b/cinelerra-5.1/cinelerra/assetpopup.C index 2744f217..12a51429 100644 --- a/cinelerra-5.1/cinelerra/assetpopup.C +++ b/cinelerra-5.1/cinelerra/assetpopup.C @@ -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; } diff --git a/cinelerra-5.1/cinelerra/assetpopup.h b/cinelerra-5.1/cinelerra/assetpopup.h index 0196bbbb..b68b379e 100644 --- a/cinelerra-5.1/cinelerra/assetpopup.h +++ b/cinelerra-5.1/cinelerra/assetpopup.h @@ -59,7 +59,7 @@ public: AssetPopupBuildIndex *index; AssetPopupView *view; AssetPopupViewWindow *view_window; - AssetListFormat *format; +// AssetListFormat *format; }; class AssetPopupInfo : public BC_MenuItem diff --git a/cinelerra-5.1/cinelerra/batchrender.C b/cinelerra-5.1/cinelerra/batchrender.C index a02a8cff..28481baa 100644 --- a/cinelerra-5.1/cinelerra/batchrender.C +++ b/cinelerra-5.1/cinelerra/batchrender.C @@ -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; diff --git a/cinelerra-5.1/cinelerra/bdcreate.C b/cinelerra-5.1/cinelerra/bdcreate.C index dc10bbc0..6a583db6 100644 --- a/cinelerra-5.1/cinelerra/bdcreate.C +++ b/cinelerra-5.1/cinelerra/bdcreate.C @@ -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); diff --git a/cinelerra-5.1/cinelerra/brender.C b/cinelerra-5.1/cinelerra/brender.C index 3a1e3f82..00888c9f 100644 --- a/cinelerra-5.1/cinelerra/brender.C +++ b/cinelerra-5.1/cinelerra/brender.C @@ -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; diff --git a/cinelerra-5.1/cinelerra/browsebutton.C b/cinelerra-5.1/cinelerra/browsebutton.C index 4d2e69b2..95f358db 100644 --- a/cinelerra-5.1/cinelerra/browsebutton.C +++ b/cinelerra-5.1/cinelerra/browsebutton.C @@ -2,42 +2,42 @@ /* * CINELERRA * Copyright (C) 2008 Adam Williams - * + * * 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() { } diff --git a/cinelerra-5.1/cinelerra/browsebutton.h b/cinelerra-5.1/cinelerra/browsebutton.h index ff8ece6f..f88a352e 100644 --- a/cinelerra-5.1/cinelerra/browsebutton.h +++ b/cinelerra-5.1/cinelerra/browsebutton.h @@ -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, diff --git a/cinelerra-5.1/cinelerra/dvdcreate.C b/cinelerra-5.1/cinelerra/dvdcreate.C index c752ba81..f6a6bc69 100644 --- a/cinelerra-5.1/cinelerra/dvdcreate.C +++ b/cinelerra-5.1/cinelerra/dvdcreate.C @@ -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); diff --git a/cinelerra-5.1/cinelerra/edlsession.C b/cinelerra-5.1/cinelerra/edlsession.C index 0930dd05..ddce17f1 100644 --- a/cinelerra-5.1/cinelerra/edlsession.C +++ b/cinelerra-5.1/cinelerra/edlsession.C @@ -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; diff --git a/cinelerra-5.1/cinelerra/edlsession.h b/cinelerra-5.1/cinelerra/edlsession.h index a919b103..81ef9fc5 100644 --- a/cinelerra-5.1/cinelerra/edlsession.h +++ b/cinelerra-5.1/cinelerra/edlsession.h @@ -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 diff --git a/cinelerra-5.1/cinelerra/exportedl.C b/cinelerra-5.1/cinelerra/exportedl.C index 45b9d408..9a5cd005 100644 --- a/cinelerra-5.1/cinelerra/exportedl.C +++ b/cinelerra-5.1/cinelerra/exportedl.C @@ -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; diff --git a/cinelerra-5.1/cinelerra/filexml.h b/cinelerra-5.1/cinelerra/filexml.h index 270b763d..4cff6758 100644 --- a/cinelerra-5.1/cinelerra/filexml.h +++ b/cinelerra-5.1/cinelerra/filexml.h @@ -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); diff --git a/cinelerra-5.1/cinelerra/formattools.C b/cinelerra-5.1/cinelerra/formattools.C index d6f27599..60295e4b 100644 --- a/cinelerra-5.1/cinelerra/formattools.C +++ b/cinelerra-5.1/cinelerra/formattools.C @@ -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. diff --git a/cinelerra-5.1/cinelerra/interfaceprefs.C b/cinelerra-5.1/cinelerra/interfaceprefs.C index 8df5e993..f8600a5d 100644 --- a/cinelerra-5.1/cinelerra/interfaceprefs.C +++ b/cinelerra-5.1/cinelerra/interfaceprefs.C @@ -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"), diff --git a/cinelerra-5.1/cinelerra/loadbalance.C b/cinelerra-5.1/cinelerra/loadbalance.C index 5765e398..fb8005bd 100644 --- a/cinelerra-5.1/cinelerra/loadbalance.C +++ b/cinelerra-5.1/cinelerra/loadbalance.C @@ -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; diff --git a/cinelerra-5.1/cinelerra/main.C b/cinelerra-5.1/cinelerra/main.C index f54edcec..caa04a83 100644 --- a/cinelerra-5.1/cinelerra/main.C +++ b/cinelerra-5.1/cinelerra/main.C @@ -41,6 +41,16 @@ #include #include +#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, diff --git a/cinelerra-5.1/cinelerra/mainmenu.C b/cinelerra-5.1/cinelerra/mainmenu.C index 5542b499..06a12bec 100644 --- a/cinelerra-5.1/cinelerra/mainmenu.C +++ b/cinelerra-5.1/cinelerra/mainmenu.C @@ -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; } diff --git a/cinelerra-5.1/cinelerra/mainmenu.h b/cinelerra-5.1/cinelerra/mainmenu.h index 25e20a1a..ebbd208b 100644 --- a/cinelerra-5.1/cinelerra/mainmenu.h +++ b/cinelerra-5.1/cinelerra/mainmenu.h @@ -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; }; diff --git a/cinelerra-5.1/cinelerra/mainsession.h b/cinelerra-5.1/cinelerra/mainsession.h index e68938d9..de08e5aa 100644 --- a/cinelerra-5.1/cinelerra/mainsession.h +++ b/cinelerra-5.1/cinelerra/mainsession.h @@ -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; diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index 55284778..4884c641 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -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); } diff --git a/cinelerra-5.1/cinelerra/mwindow.h b/cinelerra-5.1/cinelerra/mwindow.h index 39591eec..a6fd6e55 100644 --- a/cinelerra-5.1/cinelerra/mwindow.h +++ b/cinelerra-5.1/cinelerra/mwindow.h @@ -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(); diff --git a/cinelerra-5.1/cinelerra/mwindow.inc b/cinelerra-5.1/cinelerra/mwindow.inc index 0d4975b1..74589a41 100644 --- a/cinelerra-5.1/cinelerra/mwindow.inc +++ b/cinelerra-5.1/cinelerra/mwindow.inc @@ -1,7 +1,7 @@ /* * CINELERRA - * Copyright (C) 1997-2012 Adam Williams + * Copyright (C) 1997-2016 Adam Williams * * 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 diff --git a/cinelerra-5.1/cinelerra/performanceprefs.C b/cinelerra-5.1/cinelerra/performanceprefs.C index 99268702..84672769 100644 --- a/cinelerra-5.1/cinelerra/performanceprefs.C +++ b/cinelerra-5.1/cinelerra/performanceprefs.C @@ -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, diff --git a/cinelerra-5.1/cinelerra/performanceprefs.h b/cinelerra-5.1/cinelerra/performanceprefs.h index dc02a214..ecedd28e 100644 --- a/cinelerra-5.1/cinelerra/performanceprefs.h +++ b/cinelerra-5.1/cinelerra/performanceprefs.h @@ -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: diff --git a/cinelerra-5.1/cinelerra/pluginclient.C b/cinelerra-5.1/cinelerra/pluginclient.C index 0e0637b7..731d94e3 100644 --- a/cinelerra-5.1/cinelerra/pluginclient.C +++ b/cinelerra-5.1/cinelerra/pluginclient.C @@ -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. diff --git a/cinelerra-5.1/cinelerra/preferences.C b/cinelerra-5.1/cinelerra/preferences.C index 5922414c..e7fa696e 100644 --- a/cinelerra-5.1/cinelerra/preferences.C +++ b/cinelerra-5.1/cinelerra/preferences.C @@ -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; ishbtn_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); diff --git a/cinelerra-5.1/cinelerra/preferences.h b/cinelerra-5.1/cinelerra/preferences.h index d2c21fc5..d6f1821d 100644 --- a/cinelerra-5.1/cinelerra/preferences.h +++ b/cinelerra-5.1/cinelerra/preferences.h @@ -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; diff --git a/cinelerra-5.1/cinelerra/preferencesthread.C b/cinelerra-5.1/cinelerra/preferencesthread.C index 26c92c56..a7a82873 100644 --- a/cinelerra-5.1/cinelerra/preferencesthread.C +++ b/cinelerra-5.1/cinelerra/preferencesthread.C @@ -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); diff --git a/cinelerra-5.1/cinelerra/recordgui.C b/cinelerra-5.1/cinelerra/recordgui.C index 64e2984f..2fa5d3f1 100644 --- a/cinelerra-5.1/cinelerra/recordgui.C +++ b/cinelerra-5.1/cinelerra/recordgui.C @@ -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(), diff --git a/cinelerra-5.1/cinelerra/trackcanvas.C b/cinelerra-5.1/cinelerra/trackcanvas.C index 9ec6971b..87e6f074 100644 --- a/cinelerra-5.1/cinelerra/trackcanvas.C +++ b/cinelerra-5.1/cinelerra/trackcanvas.C @@ -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(); diff --git a/cinelerra-5.1/cinelerra/trackcanvas.h b/cinelerra-5.1/cinelerra/trackcanvas.h index 9f86d81d..c7b7f846 100644 --- a/cinelerra-5.1/cinelerra/trackcanvas.h +++ b/cinelerra-5.1/cinelerra/trackcanvas.h @@ -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(); diff --git a/cinelerra-5.1/guicast/Makefile b/cinelerra-5.1/guicast/Makefile index 613aba1d..efc7f15c 100644 --- a/cinelerra-5.1/guicast/Makefile +++ b/cinelerra-5.1/guicast/Makefile @@ -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 \ diff --git a/cinelerra-5.1/guicast/bcsignals.C b/cinelerra-5.1/guicast/bcsignals.C index e7c14074..e1e5aa38 100644 --- a/cinelerra-5.1/guicast/bcsignals.C +++ b/cinelerra-5.1/guicast/bcsignals.C @@ -24,6 +24,7 @@ #include "bccmodels.h" #include "bckeyboard.h" #include "bcresources.h" +#include "cstrdup.h" #include #include @@ -41,22 +42,6 @@ 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 #include @@ -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 diff --git a/cinelerra-5.1/guicast/bcsignals.h b/cinelerra-5.1/guicast/bcsignals.h index 05d44f87..25da74f4 100644 --- a/cinelerra-5.1/guicast/bcsignals.h +++ b/cinelerra-5.1/guicast/bcsignals.h @@ -25,40 +25,18 @@ #define BCSIGNALS_H #include "arraylist.h" +#include "linklist.h" #include "bcsignals.inc" +#include "bctrace.h" #include #include #include #include -#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 index 00000000..ee1c6fa0 --- /dev/null +++ b/cinelerra-5.1/guicast/bctrace.C @@ -0,0 +1,401 @@ +#include +#include +#include +#include + +#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 index 00000000..5cbf0f53 --- /dev/null +++ b/cinelerra-5.1/guicast/bctrace.h @@ -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 + + +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 { +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 { +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 { +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 index 00000000..967aa253 --- /dev/null +++ b/cinelerra-5.1/guicast/bctrace.inc @@ -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 diff --git a/cinelerra-5.1/guicast/bctumble.C b/cinelerra-5.1/guicast/bctumble.C index 65b68a6f..7dd78161 100644 --- a/cinelerra-5.1/guicast/bctumble.C +++ b/cinelerra-5.1/guicast/bctumble.C @@ -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(); diff --git a/cinelerra-5.1/guicast/bcwindowbase.C b/cinelerra-5.1/guicast/bcwindowbase.C index b6d54fe0..b4e42685 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.C +++ b/cinelerra-5.1/guicast/bcwindowbase.C @@ -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; diff --git a/cinelerra-5.1/guicast/bcwindowbase.h b/cinelerra-5.1/guicast/bcwindowbase.h index aeaba388..c2ed7abc 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.h +++ b/cinelerra-5.1/guicast/bcwindowbase.h @@ -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); diff --git a/cinelerra-5.1/guicast/clip.h b/cinelerra-5.1/guicast/clip.h index d9b64fa1..8a7d5c3b 100644 --- a/cinelerra-5.1/guicast/clip.h +++ b/cinelerra-5.1/guicast/clip.h @@ -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 diff --git a/cinelerra-5.1/guicast/condition.C b/cinelerra-5.1/guicast/condition.C index f45a9cd8..15bc0239 100644 --- a/cinelerra-5.1/guicast/condition.C +++ b/cinelerra-5.1/guicast/condition.C @@ -19,9 +19,7 @@ * */ -#ifndef NO_GUICAST #include "bcsignals.h" -#endif #include "condition.h" #include @@ -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) diff --git a/cinelerra-5.1/guicast/condition.h b/cinelerra-5.1/guicast/condition.h index 1fd455e2..bae5acfc 100644 --- a/cinelerra-5.1/guicast/condition.h +++ b/cinelerra-5.1/guicast/condition.h @@ -23,8 +23,9 @@ #define CONDITION_H #include +#include "bctrace.inc" -class Condition +class Condition : public trace_info { public: Condition(int init_value = 0, const char *title = 0, int is_binary = 0); diff --git a/cinelerra-5.1/guicast/mutex.C b/cinelerra-5.1/guicast/mutex.C index 6bbf279e..c6cddd76 100644 --- a/cinelerra-5.1/guicast/mutex.C +++ b/cinelerra-5.1/guicast/mutex.C @@ -22,15 +22,14 @@ #include #include -#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; } diff --git a/cinelerra-5.1/guicast/mutex.h b/cinelerra-5.1/guicast/mutex.h index f510f0dd..76a93584 100644 --- a/cinelerra-5.1/guicast/mutex.h +++ b/cinelerra-5.1/guicast/mutex.h @@ -24,8 +24,9 @@ #include #include +#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 diff --git a/cinelerra-5.1/guicast/sema.C b/cinelerra-5.1/guicast/sema.C index 4bd1de7c..aac4455d 100644 --- a/cinelerra-5.1/guicast/sema.C +++ b/cinelerra-5.1/guicast/sema.C @@ -2,21 +2,21 @@ /* * CINELERRA * Copyright (C) 2008 Adam Williams - * + * * 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; diff --git a/cinelerra-5.1/guicast/sema.h b/cinelerra-5.1/guicast/sema.h index 2d85f293..ef1eb9b0 100644 --- a/cinelerra-5.1/guicast/sema.h +++ b/cinelerra-5.1/guicast/sema.h @@ -24,8 +24,9 @@ #include +#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 diff --git a/cinelerra-5.1/guicast/thread.C b/cinelerra-5.1/guicast/thread.C index 355d23d5..2a8c3381 100644 --- a/cinelerra-5.1/guicast/thread.C +++ b/cinelerra-5.1/guicast/thread.C @@ -19,91 +19,16 @@ * */ -#ifndef NO_GUICAST #include "bcsignals.h" -#endif #include #include #include #include #include #include -#include "thread.h" - -// track unjoined threads at termination -#ifndef NO_GUICAST -#include "arraylist.h" -#include "mutex.h" #include +#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 { -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); - } -} - diff --git a/cinelerra-5.1/guicast/vframe.C b/cinelerra-5.1/guicast/vframe.C index a0a59744..7aeb079a 100644 --- a/cinelerra-5.1/guicast/vframe.C +++ b/cinelerra-5.1/guicast/vframe.C @@ -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); } diff --git a/cinelerra-5.1/guicast/vframe.h b/cinelerra-5.1/guicast/vframe.h index dc14dc87..dacbe712 100644 --- a/cinelerra-5.1/guicast/vframe.h +++ b/cinelerra-5.1/guicast/vframe.h @@ -244,8 +244,6 @@ public: - - // ================================ OpenGL functions =========================== // Defined in vframe3d.C // Location of working image if OpenGL playback diff --git a/cinelerra-5.1/plugins/interpolatevideo/interpolatevideo.C b/cinelerra-5.1/plugins/interpolatevideo/interpolatevideo.C index c70d6adb..ecc02613 100644 --- a/cinelerra-5.1/plugins/interpolatevideo/interpolatevideo.C +++ b/cinelerra-5.1/plugins/interpolatevideo/interpolatevideo.C @@ -1,6 +1,6 @@ /* * CINELERRA - * Copyright (C) 1997-2011 Adam Williams + * Copyright (C) 1997-2016 Adam Williams * * 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) diff --git a/cinelerra-5.1/plugins/interpolatevideo/opticflow.C b/cinelerra-5.1/plugins/interpolatevideo/opticflow.C index 90c472a1..8335cc2e 100644 --- a/cinelerra-5.1/plugins/interpolatevideo/opticflow.C +++ b/cinelerra-5.1/plugins/interpolatevideo/opticflow.C @@ -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 index 0d24a846..00000000 --- a/cinelerra-5.1/plugins/motion/debug +++ /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 diff --git a/cinelerra-5.1/plugins/motion/motion.C b/cinelerra-5.1/plugins/motion/motion.C index ed676803..63d02302 100644 --- a/cinelerra-5.1/plugins/motion/motion.C +++ b/cinelerra-5.1/plugins/motion/motion.C @@ -1,7 +1,7 @@ /* * CINELERRA - * Copyright (C) 2012 Adam Williams + * Copyright (C) 2016 Adam Williams * * 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; -} - - - diff --git a/cinelerra-5.1/plugins/motion/motion.h b/cinelerra-5.1/plugins/motion/motion.h index e0011d75..3ab5e7a6 100644 --- a/cinelerra-5.1/plugins/motion/motion.h +++ b/cinelerra-5.1/plugins/motion/motion.h @@ -1,8 +1,8 @@ /* * CINELERRA - * Copyright (C) 2008 Adam Williams - * + * Copyright (C) 2016 Adam Williams + * * 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 @@ -35,12 +35,11 @@ #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 cache; - Mutex *cache_lock; -}; - - - - #endif diff --git a/cinelerra-5.1/plugins/motion/motionscan.C b/cinelerra-5.1/plugins/motion/motionscan.C index b1a533ef..4ec92da4 100644 --- a/cinelerra-5.1/plugins/motion/motionscan.C +++ b/cinelerra-5.1/plugins/motion/motionscan.C @@ -1,7 +1,7 @@ /* * CINELERRA - * Copyright (C) 2012 Adam Williams + * Copyright (C) 2016 Adam Williams * * 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 @@ -19,20 +19,28 @@ * */ +#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 +#include +#include // 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)); diff --git a/cinelerra-5.1/plugins/motion/motionscan.h b/cinelerra-5.1/plugins/motion/motionscan.h index 8e756ee3..f358531f 100644 --- a/cinelerra-5.1/plugins/motion/motionscan.h +++ b/cinelerra-5.1/plugins/motion/motionscan.h @@ -1,7 +1,7 @@ /* * CINELERRA - * Copyright (C) 2008 Adam Williams + * Copyright (C) 2016 Adam Williams * * 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 @@ -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 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 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; }; diff --git a/cinelerra-5.1/plugins/motion/motionwindow.C b/cinelerra-5.1/plugins/motion/motionwindow.C index 02972d15..289db834 100644 --- a/cinelerra-5.1/plugins/motion/motionwindow.C +++ b/cinelerra-5.1/plugins/motion/motionwindow.C @@ -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, diff --git a/cinelerra-5.1/plugins/motion/motionwindow.h b/cinelerra-5.1/plugins/motion/motionwindow.h index 4a66a1a6..c52914e4 100644 --- a/cinelerra-5.1/plugins/motion/motionwindow.h +++ b/cinelerra-5.1/plugins/motion/motionwindow.h @@ -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 index 00000000..e7b346e9 --- /dev/null +++ b/cinelerra-5.1/plugins/motion/rotatescan.C @@ -0,0 +1,471 @@ + +/* + * CINELERRA + * Copyright (C) 2016 Adam Williams + * + * 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 index 00000000..27001e34 --- /dev/null +++ b/cinelerra-5.1/plugins/motion/rotatescan.h @@ -0,0 +1,136 @@ + +/* + * CINELERRA + * Copyright (C) 2016 Adam Williams + * + * 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 + +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 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 index 00000000..d3dfd975 --- /dev/null +++ b/cinelerra-5.1/plugins/motion/rotatescan.inc @@ -0,0 +1,12 @@ +#ifndef ROTATESCAN_INC +#define ROTATESCAN_INC + + +class RotateScan; + + +#endif + + + + diff --git a/cinelerra-5.1/plugins/motion2point/motion.C b/cinelerra-5.1/plugins/motion2point/motion.C index 4130e2d8..3b6c955a 100644 --- a/cinelerra-5.1/plugins/motion2point/motion.C +++ b/cinelerra-5.1/plugins/motion2point/motion.C @@ -1,7 +1,7 @@ /* * CINELERRA - * Copyright (C) 2008 Adam Williams + * Copyright (C) 2016 Adam Williams * * 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; diff --git a/cinelerra-5.1/plugins/reframert/reframert.C b/cinelerra-5.1/plugins/reframert/reframert.C index d79e63a8..dd7ca7e1 100644 --- a/cinelerra-5.1/plugins/reframert/reframert.C +++ b/cinelerra-5.1/plugins/reframert/reframert.C @@ -1,8 +1,8 @@ /* * CINELERRA - * Copyright (C) 2008 Adam Williams - * + * Copyright (C) 2008-2016 Adam Williams + * * 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); diff --git a/cinelerra-5.1/plugins/resamplert/resamplert.C b/cinelerra-5.1/plugins/resamplert/resamplert.C index e6de8c34..bde3bbc6 100644 --- a/cinelerra-5.1/plugins/resamplert/resamplert.C +++ b/cinelerra-5.1/plugins/resamplert/resamplert.C @@ -1,7 +1,7 @@ /* * CINELERRA - * Copyright (C) 2010 Adam Williams + * Copyright (C) 2010-2016 Adam Williams * * 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(); } } diff --git a/cinelerra-5.1/plugins/resamplert/resamplert.h b/cinelerra-5.1/plugins/resamplert/resamplert.h index 8d7300ff..a9f6f2db 100644 --- a/cinelerra-5.1/plugins/resamplert/resamplert.h +++ b/cinelerra-5.1/plugins/resamplert/resamplert.h @@ -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; }; diff --git a/cinelerra-5.1/plugins/rotate/rotate.C b/cinelerra-5.1/plugins/rotate/rotate.C index 0ebeb60d..e97334e1 100644 --- a/cinelerra-5.1/plugins/rotate/rotate.C +++ b/cinelerra-5.1/plugins/rotate/rotate.C @@ -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