}
-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;
}
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)
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;
};
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;
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));
int AssetPopup::update()
{
- format->update();
+// format->update();
gui->collect_assets();
return 0;
}
AssetPopupBuildIndex *index;
AssetPopupView *view;
AssetPopupViewWindow *view_window;
- AssetListFormat *format;
+// AssetListFormat *format;
};
class AssetPopupInfo : public BC_MenuItem
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;
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);
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;
/*
* CINELERRA
* Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ *
*/
+#include "bcsignals.h"
#include "browsebutton.h"
#include "language.h"
#include "mutex.h"
-#include "mwindow.h"
#include "theme.h"
-BrowseButton::BrowseButton(MWindow *mwindow,
- BC_WindowBase *parent_window,
- BC_TextBox *textbox,
- int x,
- int y,
- const char *init_directory,
- const char *title,
- const char *caption,
+BrowseButton::BrowseButton(Theme *theme,
+ BC_WindowBase *parent_window,
+ BC_TextBox *textbox,
+ int x,
+ int y,
+ const char *init_directory,
+ const char *title,
+ const char *caption,
int want_directory)
- : BC_Button(x, y, mwindow->theme->get_image_set("magnify_button")),
+ : BC_Button(x, y, theme->get_image_set("magnify_button")),
Thread(1, 0, 0)
{
this->parent_window = parent_window;
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");
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();
}
-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()
{
}
#include "guicast.h"
#include "mutex.inc"
-#include "mwindow.inc"
+#include "theme.inc"
#include "thread.h"
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();
const char *caption;
const char *init_directory;
BC_TextBox *textbox;
- MWindow *mwindow;
+ Theme *theme;
BC_WindowBase *parent_window;
BrowseButtonWindow *gui;
Mutex *startup_lock;
class BrowseButtonWindow : public BC_FileBox
{
public:
- BrowseButtonWindow(MWindow *mwindow,
+ BrowseButtonWindow(Theme *theme,
BrowseButton *button,
BC_WindowBase *parent_window,
const char *init_directory,
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);
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;
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);
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);
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);
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);
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);
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;
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
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;
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);
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.
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"),
LoadClient::LoadClient(LoadServer *server)
: Thread(1, 0, 0)
{
- Thread::set_synchronous(1);
this->server = server;
done = 0;
package_number = 0;
LoadClient::LoadClient()
: Thread(1, 0, 0)
{
- Thread::set_synchronous(1);
server = 0;
done = 0;
package_number = 0;
#include <stdlib.h>
#include <string.h>
+#if 0
+#define STRC printf("==new %jd from %p\n", n, __builtin_return_address(0));
+void *operator new(size_t n) { STRC void *vp = malloc(n); bzero(vp,n); return vp; }
+void operator delete(void *t) { free(t); }
+void operator delete(void *t,size_t n) { free(t); }
+void *operator new[](size_t n) { STRC void *vp = malloc(n); bzero(vp,n); return vp; }
+void operator delete[](void *t) { free(t); }
+void operator delete[](void *t,size_t n) { free(t); }
+#endif
+
enum
{
DO_GUI,
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));
-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;
}
MWindow *mwindow;
};
-class SetBRenderStart : public BC_MenuItem
+class SetBRenderRange : public BC_MenuItem
{
public:
- SetBRenderStart(MWindow *mwindow);
+ SetBRenderRange(MWindow *mwindow);
int handle_event();
MWindow *mwindow;
};
// 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;
#include "bcdisplayinfo.h"
#include "bcsignals.h"
#include "bctimer.h"
+#include "bctrace.h"
#include "bdcreate.h"
#include "brender.h"
#include "cache.h"
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;
}
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);
}
// 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();
/*
* CINELERRA
- * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 1997-2016 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
+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,
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:
{
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.
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;
for( int i=0; i<that->shbtn_prefs.size(); ++i )
this->shbtn_prefs.append(new ShBtnPref(*that->shbtn_prefs[i]));
cache_size = that->cache_size;
+ project_smp = that->project_smp;
force_uniprocessor = that->force_uniprocessor;
trap_sigsegv = that->trap_sigsegv;
trap_sigintr = that->trap_sigintr;
+ 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);
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);
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;
#include "asset.h"
#include "audiodevice.inc"
#include "bcsignals.h"
+#include "bctrace.h"
#include "cache.h"
#include "cplayback.h"
#include "cwindow.h"
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);
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(),
//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());
}
}
}
// Loop points
draw_loop_points();
- draw_brender_start();
+ draw_brender_range();
// Highlighted areas
draw_highlighting();
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();
$(OBJDIR)/bctheme.o \
$(OBJDIR)/bctitle.o \
$(OBJDIR)/bctoggle.o \
+ $(OBJDIR)/bctrace.o \
$(OBJDIR)/bctumble.o \
$(OBJDIR)/bcwindow.o \
$(OBJDIR)/bcwindow3d.o \
$(OBJDIR)/filesystem.o \
$(OBJDIR)/mutex.o \
$(OBJDIR)/rotateframe.o \
- $(OBJDIR)/sema.o \
$(OBJDIR)/thread.o \
$(OBJDIR)/testobject.o \
$(OBJDIR)/bctimer.o \
#include "bccmodels.h"
#include "bckeyboard.h"
#include "bcresources.h"
+#include "cstrdup.h"
#include <ctype.h>
#include <dirent.h>
BC_Signals* BC_Signals::global_signals = 0;
static int signal_done = 0;
-static int table_id = 0;
-
-static bc_locktrace_t* new_bc_locktrace(void *ptr,
- const char *title,
- const char *location)
-{
- bc_locktrace_t *result = (bc_locktrace_t*)malloc(sizeof(bc_locktrace_t));
- result->ptr = ptr;
- result->title = title;
- result->location = location;
- result->is_owner = 0;
- result->id = table_id++;
- result->tid = pthread_self();
- return result;
-}
-
static struct sigaction old_segv = {0, }, old_intr = {0, };
static void handle_dump(int n, siginfo_t * info, void *sc);
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);
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[] =
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);
}
}
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);
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)
{
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();
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);
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)
{
return signal_titles[number];
}
-#define TOTAL_TRACES 16
-
-void BC_Signals::new_trace(const char *text)
-{
- if(!global_signals) return;
- pthread_mutex_lock(lock);
-
-// Wrap around
- if(execution_table.size >= TOTAL_TRACES)
- {
- overwrite_table(&execution_table, strdup(text));
-// clear_table(&execution_table, 1);
- }
- else
- {
- append_table(&execution_table, strdup(text));
- }
- pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::new_trace(const char *file, const char *function, int line)
-{
- char string[BCTEXTLEN];
- snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
- new_trace(string);
-}
-
-void BC_Signals::delete_traces()
-{
- if(!global_signals) return;
- pthread_mutex_lock(lock);
- clear_table(&execution_table, 0);
- pthread_mutex_unlock(lock);
-}
-
-// no canceling with lock held
-void BC_Signals::lock_locks(const char *s)
-{
- pthread_mutex_lock(lock);
- last_lock_thread = pthread_self();
- last_lock_title = s;
- last_lock_location = 0;
-}
-
-void BC_Signals::unlock_locks()
-{
- pthread_mutex_unlock(lock);
-}
-
-#define TOTAL_LOCKS 256
-
-int BC_Signals::set_lock(void *ptr,
- const char *title,
- const char *location)
-{
- if(!global_signals) return 0;
- bc_locktrace_t *table = 0;
- int id_return = 0;
-
- pthread_mutex_lock(lock);
- last_lock_thread = pthread_self();
- last_lock_title = title;
- last_lock_location = location;
- if(lock_table.size >= TOTAL_LOCKS)
- clear_table(&lock_table, 0);
-
-// Put new lock entry
- table = new_bc_locktrace(ptr, title, location);
- append_table(&lock_table, table);
- id_return = table->id;
-
- pthread_mutex_unlock(lock);
- return id_return;
-}
-
-void BC_Signals::set_lock2(int table_id)
-{
- if(!global_signals) return;
-
- bc_locktrace_t *table = 0;
- pthread_mutex_lock(lock);
- for(int i = lock_table.size - 1; i >= 0; i--)
- {
- table = (bc_locktrace_t*)lock_table.values[i];
-// Got it. Hasn't been unlocked/deleted yet.
- if(table->id == table_id)
- {
- table->is_owner = 1;
- table->tid = pthread_self();
- pthread_mutex_unlock(lock);
- return;
- }
- }
- pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::unset_lock2(int table_id)
-{
- if(!global_signals) return;
-
- bc_locktrace_t *table = 0;
- pthread_mutex_lock(lock);
- for(int i = lock_table.size - 1; i >= 0; i--)
- {
- table = (bc_locktrace_t*)lock_table.values[i];
- if(table->id == table_id)
- {
- clear_table_entry(&lock_table, i, 1);
- break;
- }
- }
- pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::unset_lock(void *ptr)
-{
- if(!global_signals) return;
-
- bc_locktrace_t *table = 0;
- pthread_mutex_lock(lock);
-
-// Take off currently held entry
- for(int i = 0; i < lock_table.size; i++)
- {
- table = (bc_locktrace_t*)lock_table.values[i];
- if(table->ptr == ptr)
- {
- if(table->is_owner)
- {
- clear_table_entry(&lock_table, i, 1);
- break;
- }
- }
- }
-
- pthread_mutex_unlock(lock);
-}
-
-
-void BC_Signals::unset_all_locks(void *ptr)
-{
- if(!global_signals) return;
- pthread_mutex_lock(lock);
-// Take off previous lock entry
- for(int i = 0; i < lock_table.size; )
- {
- bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
- if(table->ptr == ptr)
- {
- clear_table_entry(&lock_table, i, 1);
- continue;
- }
- ++i;
- }
- pthread_mutex_unlock(lock);
-}
-
-void BC_Signals::clear_locks_tid(pthread_t tid)
-{
- if(!global_signals) return;
- pthread_mutex_lock(lock);
-// Take off previous lock entry
- for(int i = 0; i < lock_table.size; )
- {
- bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
- if(table->tid == tid)
- {
- clear_table_entry(&lock_table, i, 1);
- continue;
- }
- ++i;
- }
- pthread_mutex_unlock(lock);
-}
-
-
-void BC_Signals::enable_memory()
-{
- trace_memory = 1;
-}
-
-void BC_Signals::disable_memory()
-{
- trace_memory = 0;
-}
-
-
-void BC_Signals::set_buffer(int size, void *ptr, const char* location)
-{
- if(!global_signals) return;
- if(!trace_memory) return;
-
-//printf("BC_Signals::set_buffer %p %s\n", ptr, location);
- pthread_mutex_lock(lock);
- append_table(&memory_table, new_bc_buffertrace(size, ptr, location));
- pthread_mutex_unlock(lock);
-}
-
-int BC_Signals::unset_buffer(void *ptr)
-{
- if(!global_signals) return 0;
- if(!trace_memory) return 0;
-
- int ret = 1;
- pthread_mutex_lock(lock);
- for(int i = 0; i < memory_table.size; i++)
- {
- if(((bc_buffertrace_t*)memory_table.values[i])->ptr == ptr)
- {
-//printf("BC_Signals::unset_buffer %p\n", ptr);
- clear_table_entry(&memory_table, i, 1);
- ret = 0;
- break;
- }
- }
-
- pthread_mutex_unlock(lock);
-// fprintf(stderr, "BC_Signals::unset_buffer buffer %p not found.\n", ptr);
- return ret;
-}
-
#include <ucontext.h>
#include <sys/wait.h>
}
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);
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
#define BCSIGNALS_H
#include "arraylist.h"
+#include "linklist.h"
#include "bcsignals.inc"
+#include "bctrace.h"
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <X11/Xlib.h>
-#define TRON(x) BC_Signals::new_function(x);
-#define TROFF(x) BC_Signals::delete_function(x);
-
// BC_Signals must be initialized at the start of every program using
// debugging.
-//#define ENABLE_TRACE
-#define TRACE_LOCKS
-//#ifdef TRACE_LOCKS
-//#undef TRACE_LOCKS
-//#endif
-//#define TRACE_MEMORY
-
-// Need to use structs to avoid the memory manager.
-// One of these tables is created every time someone locks a lock.
-// After successfully locking, the table is flagged as being the owner of the lock.
-// In the unlock function, the table flagged as the owner of the lock is deleted.
-typedef struct
-{
- void *ptr;
- const char *title;
- const char *location;
- int is_owner;
- int id;
- pthread_t tid;
-} bc_locktrace_t;
-
-class BC_Signals
+class BC_Signals : public BC_Trace
{
int (*old_err_handler)(Display *, XErrorEvent *);
static int x_error_handler(Display *display, XErrorEvent *event);
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);
static bool trap_sigsegv, trap_sigintr;
};
-
#endif
--- /dev/null
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "bctrace.h"
+
+BC_Trace *BC_Trace::global_trace = 0;
+int trace_memory = 0;
+int trace_locks = 1;
+
+BC_Trace::BC_Trace()
+{
+}
+BC_Trace::~BC_Trace()
+{
+}
+
+bc_trace_mutex execution_table;
+bc_trace_mutex memory_table;
+bc_trace_mutex lock_table;
+bc_trace_list lock_free;
+bc_trace_mutex file_table;
+
+// incase lock set after task ends
+static pthread_t last_lock_thread = 0;
+static const char *last_lock_title = 0;
+static const char *last_lock_location = 0;
+
+trace_item::trace_item(bc_trace_t &t) : table(t) { ++table.size; }
+trace_item::~trace_item() { --table.size; }
+
+extern "C" void dump()
+{
+ BC_Trace::dump_traces();
+ BC_Trace::dump_locks();
+ BC_Trace::dump_buffers();
+}
+
+#define TOTAL_TRACES 16
+
+void BC_Trace::new_trace(const char *text)
+{
+ if(!global_trace) return;
+ execution_table.lock();
+ execution_item *it;
+ if( execution_table.size >= TOTAL_TRACES ) {
+ it = (execution_item *)execution_table.first;
+ execution_table.remove_pointer(it);
+ }
+ else
+ it = new execution_item();
+ it->set(text);
+ execution_table.append(it);
+ execution_table.unlock();
+}
+
+void BC_Trace::new_trace(const char *file, const char *function, int line)
+{
+ char string[BCTEXTLEN];
+ snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
+ new_trace(string);
+}
+
+void BC_Trace::delete_traces()
+{
+ if(!global_trace) return;
+ execution_table.lock();
+ execution_table.clear();
+ execution_table.unlock();
+}
+
+void BC_Trace::enable_locks()
+{
+ lock_table.lock();
+ trace_locks = 1;
+ lock_table.unlock();
+}
+
+void BC_Trace::disable_locks()
+{
+ lock_table.lock();
+ trace_locks = 0;
+ while( lock_table.last ) {
+ lock_item *p = (lock_item*)lock_table.last;
+ p->info->trace = 0;
+ lock_table.remove_pointer(p); lock_free.append(p);
+ }
+ lock_free.clear();
+ lock_table.unlock();
+}
+
+// no canceling with lock held
+void BC_Trace::lock_locks(const char *s)
+{
+ lock_table.lock();
+ last_lock_thread = pthread_self();
+ last_lock_title = s;
+ last_lock_location = 0;
+}
+
+void BC_Trace::unlock_locks()
+{
+ lock_table.unlock();
+}
+
+#define TOTAL_LOCKS 256
+
+int BC_Trace::set_lock(const char *title, const char *loc, trace_info *info)
+{
+ if( !global_trace || !trace_locks ) return 0;
+ lock_table.lock();
+ last_lock_thread = pthread_self();
+ last_lock_title = title;
+ last_lock_location = loc;
+ lock_item *it;
+ if( lock_table.size >= TOTAL_LOCKS ) {
+ it = (lock_item*)lock_table.first;
+ lock_table.remove_pointer(it);
+ }
+ else if( (it=(lock_item*)lock_free.first) != 0 )
+ lock_free.remove_pointer(it);
+ else
+ it = new lock_item();
+ it->set(info, title, loc);
+ lock_table.append(it);
+ info->trace = (void *)it;
+ lock_table.unlock();
+ return it->id;
+}
+
+void BC_Trace::set_lock2(int table_id, trace_info *info)
+{
+ if( !global_trace || !trace_locks ) return;
+ lock_table.lock();
+ lock_item *p = (lock_item *)info->trace;
+ if( !p || p->id != table_id ) {
+ p = (lock_item*)lock_table.last;
+ while( p && p->id != table_id ) p = (lock_item*)p->previous;
+ }
+ if( p ) {
+ info->trace = (void *)p;
+ p->is_owner = 1;
+ p->tid = pthread_self();
+ }
+ lock_table.unlock();
+}
+
+void BC_Trace::unset_lock2(int table_id, trace_info *info)
+{
+ if( !global_trace || !trace_locks ) return;
+ lock_table.lock();
+ lock_item *p = (lock_item *)info->trace;
+ if( !p || p->id != table_id ) {
+ p = (lock_item*)lock_table.last;
+ while( p && p->id != table_id ) p = (lock_item*)p->previous;
+ }
+ else
+ info->trace = 0;
+ if( p ) { lock_table.remove_pointer(p); lock_free.append(p); }
+ lock_table.unlock();
+}
+
+void BC_Trace::unset_lock(trace_info *info)
+{
+ if( !global_trace || !trace_locks ) return;
+ lock_table.lock();
+ lock_item *p = (lock_item *)info->trace;
+ if( !p || p->info!=info || !p->is_owner ) {
+ p = (lock_item*)lock_table.last;
+ while( p && ( p->info!=info || !p->is_owner ) ) p = (lock_item*)p->previous;
+ }
+ else
+ info->trace = 0;
+ if( p ) { lock_table.remove_pointer(p); lock_free.append(p); }
+ lock_table.unlock();
+}
+
+
+void BC_Trace::unset_all_locks(trace_info *info)
+{
+ if( !global_trace || !trace_locks ) return;
+ lock_table.lock();
+ lock_item *p = (lock_item*)lock_table.first;
+ while( p ) {
+ lock_item *lp = p; p = (lock_item*)p->next;
+ if( lp->info != info ) continue;
+ lock_table.remove_pointer(p); lock_free.append(p);
+ }
+ lock_table.unlock();
+}
+
+void BC_Trace::clear_locks_tid(pthread_t tid)
+{
+ if( !global_trace || !trace_locks ) return;
+ lock_table.lock();
+ lock_item *p = (lock_item*)lock_table.first;
+ while( p ) {
+ lock_item *lp = p; p = (lock_item*)p->next;
+ if( lp->tid != tid ) continue;
+ lock_table.remove_pointer(p); lock_free.append(p);
+ }
+ lock_table.unlock();
+}
+
+
+void BC_Trace::enable_memory()
+{
+ trace_memory = 1;
+}
+
+void BC_Trace::disable_memory()
+{
+ trace_memory = 0;
+}
+
+
+void BC_Trace::set_buffer(int size, void *ptr, const char* loc)
+{
+ if(!global_trace) return;
+ if(!trace_memory) return;
+ memory_table.lock();
+//printf("BC_Trace::set_buffer %p %s\n", ptr, loc);
+ memory_table.append(new memory_item(size, ptr, loc));
+ memory_table.unlock();
+}
+
+int BC_Trace::unset_buffer(void *ptr)
+{
+ if(!global_trace) return 0;
+ if(!trace_memory) return 0;
+ memory_table.lock();
+ memory_item *p = (memory_item*)memory_table.first;
+ for( ; p!=0 && p->ptr!=ptr; p=(memory_item*)p->next );
+ if( p ) delete p;
+ memory_table.unlock();
+ return !p ? 1 : 0;
+}
+
+#ifdef TRACE_MEMORY
+
+void* operator new(size_t size)
+{
+ void *result = malloc(size);
+ BUFFER(size, result, "new");
+ return result;
+}
+
+void* operator new[](size_t size)
+{
+ void *result = malloc(size);
+ BUFFER(size, result, "new []");
+ return result;
+}
+
+void operator delete(void *ptr)
+{
+ UNBUFFER(ptr);
+ free(ptr);
+}
+
+void operator delete[](void *ptr)
+{
+ UNBUFFER(ptr);
+ free(ptr);
+}
+
+#endif
+
+void BC_Trace::dump_traces(FILE *fp)
+{
+// Dump trace table
+ for( trace_item *tp=execution_table.first; tp!=0; tp=tp->next ) {
+ execution_item *p=(execution_item*)tp;
+ fprintf(fp," %s\n", (char*)p->value);
+ }
+}
+
+void BC_Trace::dump_locks(FILE *fp)
+{
+// Dump lock table
+#ifdef TRACE_LOCKS
+ fprintf(fp,"signal_entry: lock table size=%d\n", lock_table.size);
+ for( trace_item *tp=lock_table.first; tp!=0; tp=tp->next ) {
+ lock_item *p=(lock_item*)tp;
+ fprintf(fp," %p %s %s %p%s\n", p->info, p->title,
+ p->loc, (void*)p->tid, p->is_owner ? " *" : "");
+ }
+#endif
+}
+
+void BC_Trace::dump_buffers(FILE *fp)
+{
+#ifdef TRACE_MEMORY
+ memory_table.lock();
+// Dump buffer table
+ fprintf(fp,"BC_Trace::dump_buffers: buffer table size=%d\n", memory_table.size);
+ for( trace_item *tp=memory_table.first; tp!=0; tp=tp->next ) {
+ memory_item *p=(memory_item*)tp;
+ fprintf(fp," %d %p %s\n", p->size, p->ptr, p->loc);
+ }
+ memory_table.unlock();
+#endif
+}
+
+void BC_Trace::delete_temps()
+{
+ file_table.lock();
+ if( file_table.size )
+ printf("BC_Trace::delete_temps: deleting %d temp files\n", file_table.size);
+ while( file_table.first ) {
+ file_item *p = (file_item*)file_table.first;
+ printf(" %s\n", p->value);
+ ::remove(p->value);
+ delete p;
+ }
+ file_table.unlock();
+}
+
+void BC_Trace::reset_locks()
+{
+ lock_table.unlock();
+}
+
+void BC_Trace::set_temp(char *string)
+{
+ file_table.lock();
+ file_item *it = new file_item();
+ it->set(string);
+ file_table.append(it);
+ file_table.unlock();
+}
+
+void BC_Trace::unset_temp(char *string)
+{
+ file_table.lock();
+ file_item *p = (file_item *)file_table.last;
+ for( ; p!=0 && strcmp(p->value,string); p=(file_item*)p->previous );
+ if( p ) delete p;
+ file_table.unlock();
+}
+
+
+#ifdef TRACE_THREADS
+
+TheLock TheLocker::the_lock;
+TheList TheList::the_list;
+TheChk TheChk::the_chk;
+
+int lock_item::table_id = 0;
+
+void TheList::dbg_add(pthread_t tid, pthread_t owner, const char *nm)
+{
+ TheLocker the_locker;
+ int i = the_list.size();
+ while( --i >= 0 && the_list[i]->tid != tid );
+ if( i >= 0 ) {
+ printf("dbg_add, dup %016lx %s %s\n",
+ (unsigned long)tid, nm, the_list[i]->name);
+ return;
+ }
+ the_list.append(new TheDbg(tid, owner, nm));
+}
+
+void TheList::dbg_del(pthread_t tid)
+{
+ TheLocker the_locker;
+ int i = the_list.size();
+ while( --i >= 0 && the_list[i]->tid != tid );
+ if( i < 0 ) {
+ printf("dbg_del, mis %016lx\n",(unsigned long)tid);
+ return;
+ }
+ the_list.remove_object_number(i);
+}
+
+
+void TheList::dump_threads(FILE *fp)
+{
+ int i = the_list.size();
+ while( --i >= 0 ) {
+ fprintf(fp, "thread 0x%012lx, owner 0x%012lx, %s\n",
+ (unsigned long)the_list[i]->tid, (unsigned long)the_list[i]->owner,
+ the_list[i]->name);
+ }
+}
+
+#else
+#define dbg_add(t, o, nm) do {} while(0)
+#define dbg_del(t) do {} while(0)
+void TheList::dump_threads(FILE *fp)
+{
+}
+#endif
+
+void BC_Trace::dump_threads(FILE *fp)
+{
+ TheList::dump_threads(fp);
+}
+
+
--- /dev/null
+#ifndef __BC_TRACE_H__
+#define __BC_TRACE_H__
+
+#include "arraylist.h"
+#include "linklist.h"
+#include "bctrace.inc"
+#include "bcwindowbase.inc"
+#include "cstrdup.h"
+#include <pthread.h>
+
+
+class BC_Trace
+{
+public:
+ BC_Trace();
+ ~BC_Trace();
+
+ static BC_Trace *global_trace;
+ static void reset_locks();
+
+ static void delete_temps();
+ static void set_temp(char *string);
+ static void unset_temp(char *string);
+
+ static void enable_locks();
+ static void disable_locks();
+ static int set_lock(const char *title, const char *location, trace_info *info);
+ static void set_lock2(int table_id, trace_info *info);
+ static void unset_lock2(int table_id, trace_info *info);
+ static void unset_lock(trace_info *info);
+// Used in lock destructors so takes away all references
+ static void unset_all_locks(trace_info *info);
+ static void clear_locks_tid(pthread_t tid);
+
+ static void new_trace(const char *text);
+ static void new_trace(const char *file, const char *function, int line);
+ static void delete_traces();
+
+ static void enable_memory();
+ static void disable_memory();
+ static void set_buffer(int size, void *ptr, const char* location);
+// This one returns 1 if the buffer wasn't found.
+ static int unset_buffer(void *ptr);
+ static void lock_locks(const char *s);
+ static void unlock_locks();
+
+ static void dump_traces(FILE *fp=stdout);
+ static void dump_locks(FILE *fp=stdout);
+ static void dump_buffers(FILE *fp=stdout);
+ static void dump_threads(FILE *fp=stdout);
+};
+
+class bc_trace_list : public List<trace_item> {
+public:
+ void clear() { while( last ) remove(last); }
+ bc_trace_list() {}
+ ~bc_trace_list() { clear(); }
+};
+
+class bc_trace_t : public bc_trace_list {
+public:
+ int size;
+ bc_trace_t() : size(0) {}
+ ~bc_trace_t() {}
+};
+
+class bc_trace_spin : public bc_trace_t {
+ pthread_spinlock_t spin;
+public:
+ void *operator new(size_t n) { return (void*) malloc(n); }
+ void operator delete(void *t, size_t n) { free(t); }
+
+ void lock() { pthread_spin_lock(&spin); }
+ void unlock() { pthread_spin_unlock(&spin); }
+ bc_trace_spin() { pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE); }
+ ~bc_trace_spin() { pthread_spin_destroy(&spin); }
+};
+
+class bc_trace_mutex : public bc_trace_t {
+ pthread_mutex_t mutex;
+public:
+ void *operator new(size_t n) { return (void*) malloc(n); }
+ void operator delete(void *t, size_t n) { free(t); }
+
+ void lock() { pthread_mutex_lock(&mutex); }
+ void unlock() { pthread_mutex_unlock(&mutex); }
+ bc_trace_mutex() { pthread_mutex_init(&mutex, 0); }
+ ~bc_trace_mutex() { pthread_mutex_destroy(&mutex); }
+};
+
+extern bc_trace_mutex execution_table;
+extern bc_trace_mutex memory_table;
+extern bc_trace_mutex lock_table;
+extern bc_trace_mutex file_table;
+extern "C" void dump();
+
+class trace_item : public ListItem<trace_item> {
+public:
+ bc_trace_t &table;
+ trace_item(bc_trace_t &t);
+ ~trace_item();
+};
+
+class execution_item : public trace_item {
+public:
+ void *operator new(size_t n) { return (void*) malloc(n); }
+ void operator delete(void *t, size_t n) { free(t); }
+
+ const char *value;
+ void clear() { delete [] value; value = 0; }
+ void set(const char *v) { delete [] value; value = cstrdup(v); }
+
+ execution_item() : trace_item(execution_table) { value = 0; }
+ ~execution_item() { clear(); }
+};
+
+class lock_item : public trace_item {
+ static int table_id;
+public:
+ void *operator new(size_t n) { return (void*) malloc(n); }
+ void operator delete(void *t, size_t n) { free(t); }
+
+ trace_info *info;
+ const char *title;
+ const char *loc;
+ int is_owner;
+ int id;
+ pthread_t tid;
+ void set(trace_info *info, const char *title, const char *loc) {
+ this->info = info; this->title = title;
+ this->loc = loc; this->is_owner = 0;
+ this->id = table_id++; this->tid = pthread_self();
+ }
+ void clear() {
+ this->info = 0; this->title = 0; this->loc = 0;
+ this->is_owner = 0; this->id = -1; this->tid = 0;
+ }
+
+ lock_item() : trace_item(lock_table) { clear(); }
+ ~lock_item() {}
+};
+
+class memory_item : public trace_item {
+public:
+ void *operator new(size_t n) { return (void*) malloc(n); }
+ void operator delete(void *t, size_t n) { free(t); }
+
+ int size;
+ void *ptr;
+ const char *loc;
+
+ memory_item(int size, void *ptr, const char *loc)
+ : trace_item(memory_table) {
+ this->size = size; this->ptr = ptr; this->loc = loc;
+ }
+ ~memory_item() {}
+};
+
+class file_item : public trace_item {
+public:
+ void *operator new(size_t n) { return (void*) malloc(n); }
+ void operator delete(void *t, size_t n) { free(t); }
+
+ const char *value;
+ void clear() { delete [] value; value = 0; }
+ void set(const char *v) { delete [] value; value = cstrdup(v); }
+
+ file_item() : trace_item(file_table) { value = 0; }
+ ~file_item() { clear(); }
+};
+
+// track unjoined threads at termination
+#ifdef TRACE_THREADS
+
+class TheLock {
+public:
+ pthread_mutex_t the_lock;
+
+ void lock() { pthread_mutex_lock(&the_lock); }
+ void unlock() { pthread_mutex_unlock(&the_lock); }
+
+ TheLock() {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutex_init(&the_lock, &attr);
+ }
+ ~TheLock() {
+ pthread_mutex_destroy(&the_lock);
+ }
+};
+
+class TheLocker {
+public:
+ static TheLock the_lock;
+
+ TheLocker() { the_lock.lock(); }
+ ~TheLocker() { the_lock.unlock(); }
+};
+
+class TheDbg {
+public:
+ pthread_t tid, owner; const char *name;
+ TheDbg(pthread_t t, pthread_t o, const char *nm) { tid = t; owner = o; name = nm; }
+ ~TheDbg() {}
+};
+
+
+class TheList : public ArrayList<TheDbg *> {
+public:
+ static TheList the_list;
+ static void dump_threads(FILE *fp);
+ static void dbg_add(pthread_t tid, pthread_t owner, const char *nm);
+ static void dbg_del(pthread_t tid);
+
+ TheList() {}
+ ~TheList() {
+ TheLocker the_locker;
+ remove_all_objects();
+ }
+};
+
+class TheChk {
+public:
+ static TheChk the_chk;
+
+ TheChk() {}
+ ~TheChk() {
+ int i = TheList::the_list.size();
+ if( !i ) return;
+ printf("unjoined tids / owner %d\n", i);
+ while( --i >= 0 ) printf(" %016lx / %016lx %s\n",
+ (unsigned long)TheList::the_list[i]->tid,
+ (unsigned long)TheList::the_list[i]->owner,
+ TheList::the_list[i]->name);
+ }
+};
+
+#endif
+
+#endif
--- /dev/null
+#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
{
//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();
done = 0;
done_set = 0;
window_running = 0;
+ display_lock_owner = 0;
test_keypress = 0;
keys_return[0] = 0;
is_deleting = 0;
#include "bctimer.inc"
#include "bctitle.inc"
#include "bctoggle.inc"
+#include "bctrace.inc"
#include "bctumble.inc"
#include "bcwindow.inc"
#include "bcwindowbase.inc"
// Windows, subwindows, popupwindows inherit from this
-class BC_WindowBase
+class BC_WindowBase : public trace_info
{
public:
BC_WindowBase(int opts=0);
#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
*
*/
-#ifndef NO_GUICAST
#include "bcsignals.h"
-#endif
#include "condition.h"
#include <errno.h>
{
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;
{
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
-#ifndef NO_GUICAST
UNSET_ALL_LOCKS(this);
-#endif
}
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
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;
{
int result = 0;
-#ifndef NO_GUICAST
SET_LOCK(this, title, location);
-#endif
pthread_mutex_lock(&mutex);
struct timeval now;
}
#endif
-#ifndef NO_GUICAST
UNSET_LOCK2
-#endif
//printf("Condition::timed_lock 2 %d %s %s\n", result, title, location);
if( !result ) {
if(is_binary)
#define CONDITION_H
#include <pthread.h>
+#include "bctrace.inc"
-class Condition
+class Condition : public trace_info
{
public:
Condition(int init_value = 0, const char *title = 0, int is_binary = 0);
#include <stdio.h>
#include <errno.h>
-#ifndef NO_GUICAST
#include "bcsignals.h"
-#endif
#include "mutex.h"
Mutex::Mutex(const char *title, int recursive)
{
this->title = title;
+ this->trace = 0;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutex_init(&mutex, &attr);
{
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&recursive_lock);
-#ifndef NO_GUICAST
UNSET_ALL_LOCKS(this);
-#endif
}
int Mutex::lock(const char *location)
}
-#ifndef NO_GUICAST
SET_LOCK(this, title, location);
-#endif
if(pthread_mutex_lock(&mutex)) perror("Mutex::lock");
}
-#ifndef NO_GUICAST
SET_LOCK2
-#endif
return 0;
}
count = 0;
-#ifndef NO_GUICAST
UNSET_LOCK(this);
-#endif
if(pthread_mutex_unlock(&mutex)) perror("Mutex::unlock");
return 0;
else
count = 1;
-#ifndef NO_GUICAST
SET_LOCK(this, title, location);
SET_LOCK2
-#endif
return 0;
}
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;
}
#include <pthread.h>
#include <stdio.h>
+#include "bctrace.inc"
-class Mutex
+class Mutex : public trace_info
{
public:
Mutex(const char *title = 0, int recursive = 0);
~mLock() { mutex.unlock(); }
};
-
#endif
/*
* CINELERRA
* Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ *
*/
#include "bcsignals.h"
}
}
-
+
int Sema::lock(int number)
{
struct sembuf sop;
-
+
// decrease the semaphore
sop.sem_num = number;
sop.sem_op = -1;
int Sema::unlock(int number)
{
struct sembuf sop;
-
+
// decrease the semaphore
sop.sem_num = number;
sop.sem_op = 1;
#include <semaphore.h>
+#include "bctrace.inc"
-class Sema
+class Sema : public trace_info
{
public:
Sema(int init_value = 1, const char *title = 0);
-
-
-
-
-
#if 0
#endif
-
-
-
-
#endif
*
*/
-#ifndef NO_GUICAST
#include "bcsignals.h"
-#endif
#include <sys/wait.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
-#include "thread.h"
-
-// track unjoined threads at termination
-#ifndef NO_GUICAST
-#include "arraylist.h"
-#include "mutex.h"
#include <typeinfo>
+#include "thread.h"
-class MLocker {
- static Mutex the_lock;
-public:
- MLocker() { the_lock.lock(); }
- ~MLocker() { the_lock.unlock(); }
-};
-Mutex MLocker::the_lock;
-
-class the_dbg {
-public:
- pthread_t tid, owner; const char *name;
- the_dbg(pthread_t t, pthread_t o, const char *nm) { tid = t; owner = o; name = nm; }
- ~the_dbg() {}
-};
-
-
-static class the_list : public ArrayList<the_dbg*> {
-public:
- static void dump_threads(FILE *fp);
- the_list() {}
- ~the_list() {
- MLocker mlkr;
- remove_all_objects();
- }
-} thread_list;
-
-static void dbg_add(pthread_t tid, pthread_t owner, const char *nm)
-{
- MLocker mlkr;
- int i = thread_list.size();
- while( --i >= 0 && thread_list[i]->tid != tid );
- if( i >= 0 ) {
- printf("dbg_add, dup %016lx %s %s\n",
- (unsigned long)tid, nm, thread_list[i]->name);
- return;
- }
- thread_list.append(new the_dbg(tid, owner, nm));
-}
-
-static void dbg_del(pthread_t tid)
-{
- MLocker mlkr;
- int i = thread_list.size();
- while( --i >= 0 && thread_list[i]->tid != tid );
- if( i < 0 ) {
- printf("dbg_del, mis %016lx\n",(unsigned long)tid);
- return;
- }
- thread_list.remove_object_number(i);
-}
-
-static class the_chkr {
-public:
- the_chkr() {}
- ~the_chkr() {
- int i = thread_list.size();
- if( !i ) return;
- printf("unjoined tids / owner %d\n", i);
- while( --i >= 0 ) printf(" %016lx / %016lx %s\n",
- (unsigned long)thread_list[i]->tid,
- (unsigned long)thread_list[i]->owner,
- thread_list[i]->name);
- }
-} the_chk;
-#else
-#define dbg_add(t, nm) do {} while(0)
-#define dbg_del(t) do {} while(0)
-#endif
Thread::Thread(int synchronous, int realtime, int autodelete)
{
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);
}
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()
LOCK_LOCKS("Thread::cancel");
pthread_cancel(tid);
cancelled = true;
- if( !synchronous ) dbg_del(tid);
+ if( !synchronous ) TheList::dbg_del(tid);
UNLOCK_LOCKS;
}
return 0;
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;
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);
- }
-}
-
}
else {
// Have to use malloc for libpng
+//printf("==vframe %d from %p\n", size, __builtin_return_address(0));
this->data = (unsigned char *)malloc(size);
}
-
-
// ================================ OpenGL functions ===========================
// Defined in vframe3d.C
// Location of working image if OpenGL playback
/*
* CINELERRA
- * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 1997-2016 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
}
}
+//printf("InterpolateVideo::optic_flow %d %d\n", __LINE__, invalid_blocks.size());
if(invalid_blocks.size())
{
if(!blend_engine)
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
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;
+++ /dev/null
-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
/*
* CINELERRA
- * Copyright (C) 2012 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "mutex.h"
#include "overlayframe.h"
#include "rotateframe.h"
+#include "rotatescan.h"
#include "transportque.h"
REGISTER_PLUGIN(MotionMain)
-
#undef DEBUG
// #ifndef DEBUG
MotionConfig::MotionConfig()
{
- global_range_w = 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);
rotation_range == that.rotation_range &&
rotation_center == that.rotation_center &&
action_type == that.action_type &&
- global == that.global &&
+// global == that.global &&
rotate == that.rotate &&
- addtrackedframeoffset == that.addtrackedframeoffset &&
draw_vectors == that.draw_vectors &&
block_count == that.block_count &&
global_block_w == that.global_block_w &&
// rotation_block_h == that.rotation_block_h &&
EQUIV(block_x, that.block_x) &&
EQUIV(block_y, that.block_y) &&
- global_positions == that.global_positions &&
- rotate_positions == that.rotate_positions &&
+// global_positions == that.global_positions &&
+// rotate_positions == that.rotate_positions &&
magnitude == that.magnitude &&
return_speed == that.return_speed &&
rotate_return_speed == that.rotate_return_speed &&
rotation_range = that.rotation_range;
rotation_center = that.rotation_center;
action_type = that.action_type;
- global = that.global;
+// global = that.global;
rotate = that.rotate;
- addtrackedframeoffset = that.addtrackedframeoffset;
tracking_type = that.tracking_type;
draw_vectors = that.draw_vectors;
block_count = that.block_count;
block_x = that.block_x;
block_y = that.block_y;
- global_positions = that.global_positions;
- rotate_positions = that.rotate_positions;
+// global_positions = that.global_positions;
+// rotate_positions = that.rotate_positions;
global_block_w = that.global_block_w;
global_block_h = that.global_block_h;
// rotation_block_w = that.rotation_block_w;
rotation_range = prev.rotation_range;
rotation_center = prev.rotation_center;
action_type = prev.action_type;
- global = prev.global;
+// global = prev.global;
rotate = prev.rotate;
- addtrackedframeoffset = prev.addtrackedframeoffset;
tracking_type = prev.tracking_type;
draw_vectors = prev.draw_vectors;
block_count = prev.block_count;
- global_positions = prev.global_positions;
- rotate_positions = prev.rotate_positions;
+// global_positions = prev.global_positions;
+// rotate_positions = prev.rotate_positions;
global_block_w = prev.global_block_w;
global_block_h = prev.global_block_h;
// rotation_block_w = prev.rotation_block_w;
{
engine = 0;
rotate_engine = 0;
- motion_rotate = 0;
+// motion_rotate = 0;
total_dx = 0;
total_dy = 0;
total_angle = 0;
current_rotate_ref = 0;
rotate_target_src = 0;
rotate_target_dst = 0;
-
- config.set_cpus(get_project_smp() + 1);
}
MotionMain::~MotionMain()
delete [] search_area;
delete temp_frame;
delete rotate_engine;
- delete motion_rotate;
+// delete motion_rotate;
delete prev_global_ref;
{
thread->window->lock_window("MotionMain::update_gui");
- char string[BCTEXTLEN];
- sprintf(string, "%d", config.global_positions);
- ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
- sprintf(string, "%d", config.rotate_positions);
- ((MotionWindow*)thread->window)->rotation_search_positions->set_text(string);
+// char string[BCTEXTLEN];
+// sprintf(string, "%d", config.global_positions);
+// ((MotionWindow*)thread->window)->global_search_positions->set_text(string);
+// sprintf(string, "%d", config.rotate_positions);
+// ((MotionWindow*)thread->window)->rotation_search_positions->set_text(string);
((MotionWindow*)thread->window)->global_block_w->update(config.global_block_w);
((MotionWindow*)thread->window)->global_block_h->update(config.global_block_h);
output.tag.set_title("MOTION");
output.tag.set_property("BLOCK_COUNT", config.block_count);
- output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
- output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
+// output.tag.set_property("GLOBAL_POSITIONS", config.global_positions);
+// output.tag.set_property("ROTATE_POSITIONS", config.rotate_positions);
output.tag.set_property("GLOBAL_BLOCK_W", config.global_block_w);
output.tag.set_property("GLOBAL_BLOCK_H", config.global_block_h);
// output.tag.set_property("ROTATION_BLOCK_W", config.rotation_block_w);
output.tag.set_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
output.tag.set_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
output.tag.set_property("ACTION_TYPE", config.action_type);
- output.tag.set_property("GLOBAL", config.global);
+// output.tag.set_property("GLOBAL", config.global);
output.tag.set_property("ROTATE", config.rotate);
- output.tag.set_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
output.tag.set_property("TRACKING_TYPE", config.tracking_type);
output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
output.tag.set_property("TRACKING_OBJECT", config.tracking_object);
if(input.tag.title_is("MOTION"))
{
config.block_count = input.tag.get_property("BLOCK_COUNT", config.block_count);
- config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
- config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
+// config.global_positions = input.tag.get_property("GLOBAL_POSITIONS", config.global_positions);
+// config.rotate_positions = input.tag.get_property("ROTATE_POSITIONS", config.rotate_positions);
config.global_block_w = input.tag.get_property("GLOBAL_BLOCK_W", config.global_block_w);
config.global_block_h = input.tag.get_property("GLOBAL_BLOCK_H", config.global_block_h);
// config.rotation_block_w = input.tag.get_property("ROTATION_BLOCK_W", config.rotation_block_w);
config.rotate_magnitude = input.tag.get_property("ROTATE_MAGNITUDE", config.rotate_magnitude);
config.rotate_return_speed = input.tag.get_property("ROTATE_RETURN_SPEED", config.rotate_return_speed);
config.action_type = input.tag.get_property("ACTION_TYPE", config.action_type);
- config.global = input.tag.get_property("GLOBAL", config.global);
+// config.global = input.tag.get_property("GLOBAL", config.global);
config.rotate = input.tag.get_property("ROTATE", config.rotate);
- config.addtrackedframeoffset = input.tag.get_property("ADDTRACKEDFRAMEOFFSET", config.addtrackedframeoffset);
config.tracking_type = input.tag.get_property("TRACKING_TYPE", config.tracking_type);
config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
config.tracking_object = input.tag.get_property("TRACKING_OBJECT", config.tracking_object);
void MotionMain::process_global()
{
+ int w = current_global_ref->get_w();
+ int h = current_global_ref->get_h();
+
if(!engine) engine = new MotionScan(PluginClient::get_project_smp() + 1,
PluginClient::get_project_smp() + 1);
// Determine if frames changed
+// printf("MotionMain::process_global %d block_y=%f total_dy=%d\n",
+// __LINE__, config.block_y * h / 100, total_dy);
engine->scan_frame(current_global_ref,
prev_global_ref,
- config.global_range_w,
- 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;
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
// 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)
{
dx = -(int)(total_dx / OVERSAMPLE);
dy = -(int)(total_dy / OVERSAMPLE);
break;
- break;
case MotionScan::TRACK:
interpolation = CUBIC_LINEAR;
dx = (float)total_dx / OVERSAMPLE;
int block_x;
int block_y;
+// Always require global
// Convert the previous global reference into the previous rotation reference.
// Convert global target destination into rotation target source.
- if(config.global)
+// if(config.global)
+ if(1)
{
if(!overlayer)
overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
// Get rotation
- if(!motion_rotate)
- motion_rotate = new RotateScan(this,
- get_project_smp() + 1,
- get_project_smp() + 1);
-
- current_angle = motion_rotate->scan_frame(prev_rotate_ref,
- current_rotate_ref,
- block_x,
- block_y);
-
-
+// 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)
CLAMP(total_angle, -config.rotate_magnitude, config.rotate_magnitude);
}
- if(!config.global)
- {
+// if(!config.global)
+// {
// Transfer current reference frame to previous reference frame and update
// counter.
- prev_rotate_ref->copy_from(current_rotate_ref);
- previous_frame_number = get_source_position();
- }
+// prev_rotate_ref->copy_from(current_rotate_ref);
+// previous_frame_number = get_source_position();
+// }
}
else
{
case MotionScan::STABILIZE:
case MotionScan::STABILIZE_PIXEL:
- if(config.global)
+// if(config.global)
+ if(1)
{
// Use origin of global stabilize operation
// rotate_engine->set_pivot((int)(rotate_target_dst->get_w() *
}
+printf("MotionMain::process_rotation angle=%f\n", angle);
rotate_engine->rotate(rotate_target_dst, rotate_target_src, angle);
// overlayer->overlay(rotate_target_dst,
// prev_rotate_ref,
}
- if(!config.global && !config.rotate) skip_current = 1;
+// if(!config.global && !config.rotate) skip_current = 1;
// Get the global pointers. Here we walk through the sequence of events.
- if(config.global)
+// if(config.global)
+ if(1)
{
// Assume global only. Global reads previous frame and compares
// with current frame to get the current translation.
-
+//PRINT_TRACE
+//printf("skip_current=%d config.global=%d\n", skip_current, config.global);
if(!skip_current)
{
// Get position change from previous frame to current frame
- if(config.global) process_global();
+ /* if(config.global) */ process_global();
// Get rotation change from previous frame to current frame
if(config.rotate) process_rotation();
//frame[target_layer]->copy_from(prev_rotate_ref);
int search_x2, search_y2;
- 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;
// 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);
// search_x2,
// search_y2);
- MotionScan::clamp_scan(w,
- h,
+ MotionScan::clamp_scan(w,
+ h,
&block_x1,
&block_y1,
&block_x2,
-
-
-
-
-
-
-
-
-
-RotateScanPackage::RotateScanPackage()
-{
-}
-
-
-RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
- : LoadClient(server)
-{
- this->server = server;
- this->plugin = plugin;
- rotater = 0;
- temp = 0;
-}
-
-RotateScanUnit::~RotateScanUnit()
-{
- delete rotater;
- delete temp;
-}
-
-void RotateScanUnit::process_package(LoadPackage *package)
-{
- if(server->skip) return;
- RotateScanPackage *pkg = (RotateScanPackage*)package;
-
- if((pkg->difference = server->get_cache(pkg->angle)) < 0)
- {
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
- int color_model = server->previous_frame->get_color_model();
- int pixel_size = BC_CModels::calculate_pixelsize(color_model);
- int row_bytes = server->previous_frame->get_bytes_per_line();
-
- if(!rotater)
- rotater = new AffineEngine(1, 1);
- if(!temp) temp = new VFrame(0,
- -1,
- server->previous_frame->get_w(),
- server->previous_frame->get_h(),
- color_model,
- -1);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
-
-
-// Rotate original block size
-// rotater->set_viewport(server->block_x1,
-// server->block_y1,
-// server->block_x2 - server->block_x1,
-// server->block_y2 - server->block_y1);
- rotater->set_in_viewport(server->block_x1,
- server->block_y1,
- server->block_x2 - server->block_x1,
- server->block_y2 - server->block_y1);
- rotater->set_out_viewport(server->block_x1,
- server->block_y1,
- server->block_x2 - server->block_x1,
- server->block_y2 - server->block_y1);
-// rotater->set_pivot(server->block_x, server->block_y);
- rotater->set_in_pivot(server->block_x, server->block_y);
- rotater->set_out_pivot(server->block_x, server->block_y);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
- rotater->rotate(temp,
- server->previous_frame,
- pkg->angle);
-
-// Scan reduced block size
-//plugin->output_frame->copy_from(server->current_frame);
-//plugin->output_frame->copy_from(temp);
-// printf("RotateScanUnit::process_package %d %d %d %d %d\n",
-// __LINE__,
-// server->scan_x,
-// server->scan_y,
-// server->scan_w,
-// server->scan_h);
-// Clamp coordinates
- int x1 = server->scan_x;
- int y1 = server->scan_y;
- int x2 = x1 + server->scan_w;
- int y2 = y1 + server->scan_h;
- x2 = MIN(temp->get_w(), x2);
- y2 = MIN(temp->get_h(), y2);
- x2 = MIN(server->current_frame->get_w(), x2);
- y2 = MIN(server->current_frame->get_h(), y2);
- x1 = MAX(0, x1);
- y1 = MAX(0, y1);
-
- if(x2 > x1 && y2 > y1)
- {
- pkg->difference = MotionScan::abs_diff(
- temp->get_rows()[y1] + x1 * pixel_size,
- server->current_frame->get_rows()[y1] + x1 * pixel_size,
- row_bytes,
- x2 - x1,
- y2 - y1,
- color_model);
-//printf("RotateScanUnit::process_package %d\n", __LINE__);
- server->put_cache(pkg->angle, pkg->difference);
- }
-#if 0
- VFrame png(x2-x1, y2-y1, BC_RGB888, -1);
- png.transfer_from(temp, 0, x1, y1, x2-x1, y2-y1);
- char fn[64];
- sprintf(fn,"%s%f.png","/tmp/temp",pkg->angle); png.write_png(fn);
- png.transfer_from(server->current_frame, 0, x1, y1, x2-x1, y2-y1);
- sprintf(fn,"%s%f.png","/tmp/curr",pkg->angle); png.write_png(fn);
-printf("RotateScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%jd\n",
- server->block_x1, server->block_y1, server->block_x2 - server->block_x1, server->block_y2 - server->block_y1,
- server->block_x, server->block_y, pkg->angle, server->scan_w, server->scan_h, pkg->difference);
-#endif
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-RotateScan::RotateScan(MotionMain *plugin,
- int total_clients,
- int total_packages)
- : LoadServer(
-//1, 1
-total_clients, total_packages
-)
-{
- this->plugin = plugin;
- cache_lock = new Mutex("RotateScan::cache_lock");
-}
-
-
-RotateScan::~RotateScan()
-{
- delete cache_lock;
-}
-
-void RotateScan::init_packages()
-{
- for(int i = 0; i < get_total_packages(); i++)
- {
- RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
- pkg->angle = i *
- (scan_angle2 - scan_angle1) /
- (total_steps - 1) +
- scan_angle1;
- }
-}
-
-LoadClient* RotateScan::new_client()
-{
- return new RotateScanUnit(this, plugin);
-}
-
-LoadPackage* RotateScan::new_package()
-{
- return new RotateScanPackage;
-}
-
-
-float RotateScan::scan_frame(VFrame *previous_frame,
- VFrame *current_frame,
- int block_x,
- int block_y)
-{
- skip = 0;
- this->block_x = block_x;
- this->block_y = block_y;
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
- switch(plugin->config.tracking_type)
- {
- case MotionScan::NO_CALCULATE:
- result = plugin->config.rotation_center;
- skip = 1;
- break;
-
- case MotionScan::LOAD:
- {
- char string[BCTEXTLEN];
- sprintf(string, "%s%06jd",
- ROTATION_FILE, plugin->get_source_position());
- FILE *input = fopen(string, "r");
- if(input)
- {
- fscanf(input, "%f", &result);
- fclose(input);
- skip = 1;
- }
- else
- {
- perror("RotateScan::scan_frame LOAD");
- }
- break;
- }
- }
-
-
-
-
-
-
-
-
- this->previous_frame = previous_frame;
- this->current_frame = current_frame;
- int w = current_frame->get_w();
- int h = current_frame->get_h();
- int block_w = w * plugin->config.global_block_w / 100;
- int block_h = h * plugin->config.global_block_h / 100;
-
- if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
- if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
- if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
- if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
-
- block_x1 = this->block_x - block_w / 2;
- block_x2 = this->block_x + block_w / 2;
- block_y1 = this->block_y - block_h / 2;
- block_y2 = this->block_y + block_h / 2;
-
-// Calculate the maximum area available to scan after rotation.
-// Must be calculated from the starting range because of cache.
-// Get coords of rectangle after rotation.
- double center_x = this->block_x;
- double center_y = this->block_y;
- double max_angle = plugin->config.rotation_range;
- double base_angle1 = atan((float)block_h / block_w);
- double base_angle2 = atan((float)block_w / block_h);
- double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
- double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
- double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
- double x1 = center_x - cos(target_angle1) * radius;
- double y1 = center_y - sin(target_angle1) * radius;
- double x2 = center_x + sin(target_angle2) * radius;
- double y2 = center_y - cos(target_angle2) * radius;
- double x3 = center_x - sin(target_angle2) * radius;
- double y3 = center_y + cos(target_angle2) * radius;
-
-// Track top edge to find greatest area.
- double max_area1 = 0;
- //double max_x1 = 0;
- double max_y1 = 0;
- for(double x = x1; x < x2; x++)
- {
- double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
- if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
- {
- double area = fabs(x - center_x) * fabs(y - center_y);
- if(area > max_area1)
- {
- max_area1 = area;
- //max_x1 = x;
- max_y1 = y;
- }
- }
- }
-
-// Track left edge to find greatest area.
- double max_area2 = 0;
- double max_x2 = 0;
- //double max_y2 = 0;
- for(double y = y1; y < y3; y++)
- {
- double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
- if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
- {
- double area = fabs(x - center_x) * fabs(y - center_y);
- if(area > max_area2)
- {
- max_area2 = area;
- max_x2 = x;
- //max_y2 = y;
- }
- }
- }
-
- double max_x, max_y;
- max_x = max_x2;
- max_y = max_y1;
-
-// Get reduced scan coords
- scan_w = (int)(fabs(max_x - center_x) * 2);
- scan_h = (int)(fabs(max_y - center_y) * 2);
- scan_x = (int)(center_x - scan_w / 2);
- scan_y = (int)(center_y - scan_h / 2);
-// printf("RotateScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n",
-// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
-// printf(" angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
-
-// Determine min angle from size of block
- double angle1 = atan((double)block_h / block_w);
- double angle2 = atan((double)(block_h - 1) / (block_w + 1));
- double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
- min_angle = MAX(min_angle, MIN_ANGLE);
-
-//printf("RotateScan::scan_frame %d min_angle=%f\n", __LINE__, min_angle * 360 / 2 / M_PI);
-
- cache.remove_all_objects();
-
-
- if(!skip)
- {
- if(previous_frame->data_matches(current_frame))
- {
-//printf("RotateScan::scan_frame: frames match. Skipping.\n");
- result = plugin->config.rotation_center;
- skip = 1;
- }
- }
-
- if(!skip)
- {
-// Initial search range
- float angle_range = max_angle;
- result = plugin->config.rotation_center;
- total_steps = plugin->config.rotate_positions;
-
-
- while(angle_range >= min_angle * total_steps)
- {
- scan_angle1 = result - angle_range;
- scan_angle2 = result + angle_range;
-
-
- set_package_count(total_steps);
-//set_package_count(1);
- process_packages();
-
- int64_t min_difference = -1;
- for(int i = 0; i < get_total_packages(); i++)
- {
- RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
- if(pkg->difference < min_difference || min_difference == -1)
- {
- min_difference = pkg->difference;
- result = pkg->angle;
- }
-//break;
- }
-
- angle_range /= 2;
-
-//break;
- }
- }
-
-//printf("RotateScan::scan_frame %d\n", __LINE__);
-
- if(!skip && plugin->config.tracking_type == MotionScan::SAVE)
- {
- char string[BCTEXTLEN];
- sprintf(string, "%s%06jd",
- ROTATION_FILE, plugin->get_source_position());
- FILE *output = fopen(string, "w");
- if(output)
- {
- fprintf(output, "%f\n", result);
- fclose(output);
- }
- else
- {
- perror("RotateScan::scan_frame SAVE");
- }
- }
-
-//printf("RotateScan::scan_frame %d angle=%f\n", __LINE__, result);
-
-
-
- return result;
-}
-
-int64_t RotateScan::get_cache(float angle)
-{
- int64_t result = -1;
- cache_lock->lock("RotateScan::get_cache");
- for(int i = 0; i < cache.total; i++)
- {
- RotateScanCache *ptr = cache.values[i];
- if(fabs(ptr->angle - angle) <= MIN_ANGLE)
- {
- result = ptr->difference;
- break;
- }
- }
- cache_lock->unlock();
- return result;
-}
-
-void RotateScan::put_cache(float angle, int64_t difference)
-{
- RotateScanCache *ptr = new RotateScanCache(angle, difference);
- cache_lock->lock("RotateScan::put_cache");
- cache.append(ptr);
- cache_lock->unlock();
-}
-
-
-
-
-
-
-
-
-
-RotateScanCache::RotateScanCache(float angle, int64_t difference)
-{
- this->angle = angle;
- this->difference = difference;
-}
-
-
-
/*
* CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
#include "motionwindow.inc"
#include "overlayframe.inc"
#include "pluginvclient.h"
-#include "rotateframe.inc"
+#include "rotatescan.inc"
#include "vframe.inc"
class MotionMain;
class MotionWindow;
-class RotateScan;
// Precision of rotation
#define MIN_ANGLE 0.0001
-#define ROTATION_FILE "/tmp/r"
class MotionConfig
{
int64_t next_frame,
int64_t current_frame);
void boundaries();
- void set_cpus(int cpus);
int block_count;
int global_range_w;
// int rotation_block_w;
// int rotation_block_h;
// Number of search positions in each refinement of the log search
- int global_positions;
- int rotate_positions;
+// int global_positions;
+// int rotate_positions;
// Block position in percentage 0 - 100
double block_x;
double block_y;
int vertical_only;
int global;
int rotate;
- int addtrackedframeoffset;
// Track or stabilize, single pixel, scan only, or nothing
int action_type;
// Recalculate, no calculate, save, or load coordinates from disk
// It is moved to compensate for motion and copied to the previous_frame.
VFrame *temp_frame;
MotionScan *engine;
- RotateScan *motion_rotate;
+// RotateScan *motion_rotate;
OverlayFrame *overlayer;
AffineEngine *rotate_engine;
-
-
-
-
-
-
-
-
-
-
-
-
-
-class RotateScanPackage : public LoadPackage
-{
-public:
- RotateScanPackage();
- float angle;
- int64_t difference;
-};
-
-class RotateScanCache
-{
-public:
- RotateScanCache(float angle, int64_t difference);
- float angle;
- int64_t difference;
-};
-
-class RotateScanUnit : public LoadClient
-{
-public:
- RotateScanUnit(RotateScan *server, MotionMain *plugin);
- ~RotateScanUnit();
-
- void process_package(LoadPackage *package);
-
- RotateScan *server;
- MotionMain *plugin;
- AffineEngine *rotater;
- VFrame *temp;
-};
-
-class RotateScan : public LoadServer
-{
-public:
- RotateScan(MotionMain *plugin,
- int total_clients,
- int total_packages);
- ~RotateScan();
-
- friend class RotateScanUnit;
-
- void init_packages();
- LoadClient* new_client();
- LoadPackage* new_package();
-
-// Invoke the motion engine for a search
-// Frame before rotation
- float scan_frame(VFrame *previous_frame,
-// Frame after rotation
- VFrame *current_frame,
-// Pivot
- int block_x,
- int block_y);
- int64_t get_cache(float angle);
- void put_cache(float angle, int64_t difference);
-
-
-// Angle result
- float result;
-
-private:
- VFrame *previous_frame;
-// Frame after motion
- VFrame *current_frame;
-
- MotionMain *plugin;
- int skip;
-
-// Pivot
- int block_x;
- int block_y;
-// Block to rotate
- int block_x1;
- int block_x2;
- int block_y1;
- int block_y2;
-// Area to compare
- int scan_x;
- int scan_y;
- int scan_w;
- int scan_h;
-// Range of angles to compare
- float scan_angle1, scan_angle2;
- int total_steps;
-
- ArrayList<RotateScanCache*> cache;
- Mutex *cache_lock;
-};
-
-
-
-
#endif
/*
* CINELERRA
- * Copyright (C) 2012 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
*/
+#include "affine.h"
+#include "bcsignals.h"
#include "clip.h"
-//#include "../downsample/downsampleengine.h"
-//#include "motion.h"
#include "motionscan.h"
#include "mutex.h"
#include "vframe.h"
+
#include <math.h>
+#include <stdlib.h>
+#include <string.h>
// The module which does the actual scanning
-
-
-
+// starting level of detail
+#define STARTING_DOWNSAMPLE 16
+// minimum size in each level of detail
+#define MIN_DOWNSAMPLED_SIZE 16
+// minimum scan range
+#define MIN_DOWNSAMPLED_SCAN 4
+// scan range for subpixel mode
+#define SUBPIXEL_RANGE 4
MotionScanPackage::MotionScanPackage()
: LoadPackage()
: 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();
-}
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;
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;
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.
case MotionScan::NO_CALCULATE:
dx_result = 0;
dy_result = 0;
+ dr_result = rotation_center;
skip = 1;
break;
{
// 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;
}
break;
}
+
+
if(!skip && test_match)
{
if(previous_frame->data_matches(current_frame))
printf("MotionScan::scan_frame: data matches. skipping.\n");
dx_result = 0;
dy_result = 0;
+ dr_result = rotation_center;
skip = 1;
}
}
+
// Perform scan
if(!skip)
{
-//printf("MotionScan::scan_frame %d\n", __LINE__);
// Location of block in current frame
- int origin_offset_x = this->global_origin_x * 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,
// 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,
// scan_y1,
// scan_x2,
// scan_y2);
+
+
// Clamp the block coords before the scan so we get useful scan coords.
clamp_scan(w,
h,
&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,
// scan_y2,
// x_result,
// y_result);
+//if(y_result == 88) exit(0);
// Give up if invalid coords.
scan_x2 <= scan_x1 ||
block_x2 <= block_x1 ||
block_y2 <= block_y1)
+ {
break;
+ }
// For subpixel, the top row and left column are skipped
if(subpixel)
{
-//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
// 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);
+}
-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();
-}
{ \
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) \
{ \
case BC_YUVA8888:
ABS_DIFF(unsigned char, int64_t, 1, 4)
break;
- case BC_YUV161616:
- ABS_DIFF(uint16_t, int64_t, 1, 3)
- break;
- case BC_YUVA16161616:
- ABS_DIFF(uint16_t, int64_t, 1, 4)
- break;
}
return result;
}
0x100 / 0x100; \
temp_type current_value = *current_row++; \
difference = prev_value - current_value; \
- if(difference < 0) \
- result_temp -= difference; \
- else \
- result_temp += difference; \
+ difference *= difference; \
+ result_temp += difference; \
} \
\
/* skip alpha */ \
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,
// 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;
}
if(*scan_x1 < 0)
{
int difference = -*scan_x1;
-// *block_x1 += difference;
+#ifdef CLAMP_BLOCK
+ *block_x1 += difference;
+#endif
*scan_x2 += difference;
*scan_x1 = 0;
}
if(*scan_y1 < 0)
{
int difference = -*scan_y1;
-// *block_y1 += difference;
+#ifdef CLAMP_BLOCK
+ *block_y1 += difference;
+#endif
*scan_y2 += difference;
*scan_y1 = 0;
}
{
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));
/*
* CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define MOTIONSCAN_H
-#include "arraylist.h"
-//#include "../downsample/downsampleengine.inc"
+#include "affine.inc"
#include "loadbalance.h"
#include "vframe.inc"
#include <stdint.h>
#define OVERSAMPLE 4
#define MOTION_FILE "/tmp/m"
+#define ROTATION_FILE "/tmp/r"
class MotionScanPackage : public LoadPackage
{
MotionScanPackage();
// For multiple blocks
-// Position of stationary block
+// Position of stationary block after downsampling
int block_x1, block_y1, block_x2, block_y2;
-// Range of positions to scan
- int scan_x1, scan_y1, scan_x2, scan_y2;
+// index of rotated frame
+ int angle_step;
+
int dx;
int dy;
int64_t max_difference;
int64_t min_pixel;
int is_border;
int valid;
-// For single block
- int step;
int64_t difference1;
int64_t difference2;
-// Search position to nearest pixel
+// Search position of current package to nearest pixel with downsampling
int search_x;
int search_y;
// Subpixel of search position
int sub_y;
};
-class MotionScanCache
-{
-public:
- MotionScanCache(int x, int y, int64_t difference);
- int x, y;
- int64_t difference;
-};
-
class MotionScanUnit : public LoadClient
{
public:
~MotionScanUnit();
void process_package(LoadPackage *package);
- int64_t get_cache(int x, int y);
- void put_cache(int x, int y, int64_t difference);
+ void subpixel(MotionScanPackage *pkg);
+ void single_pixel(MotionScanPackage *pkg);
MotionScan *server;
-
- ArrayList<MotionScanCache*> cache;
- Mutex *cache_lock;
};
class MotionScan : public LoadServer
// Invoke the motion engine for a search
// Frame before motion
void scan_frame(VFrame *previous_frame,
-// Frame after motion
VFrame *current_frame,
- int global_range_w,
+ int global_range_w, // in pixels
int global_range_h,
- int global_block_w,
+ int global_block_w, // in pixels
int global_block_h,
- double block_x,
- double block_y,
+ int block_x, // in pixels
+ int block_y,
int frame_type,
int tracking_type,
int action_type,
int horizontal_only,
int vertical_only,
int source_position,
- int total_steps,
- int total_dx,
+ int total_dx, // in pixels * OVERSAMPLE
int total_dy,
- int global_origin_x,
- int global_origin_y);
- int64_t get_cache(int x, int y);
- void put_cache(int x, int y, int64_t difference);
+ int global_origin_x, // in pixels
+ int global_origin_y,
+ int do_motion,
+ int do_rotate,
+ double rotation_center, // in deg
+ double rotation_range);
static int64_t abs_diff(unsigned char *prev_ptr,
unsigned char *current_ptr,
// OVERSAMPLE
int dx_result;
int dy_result;
+ float dr_result;
enum
{
};
private:
+ void downsample_frame(VFrame *dst,
+ VFrame *src,
+ int downsample);
+ void pixel_search(int &x_result, int &y_result, double &r_result);
+ void subpixel_search(int &x_result, int &y_result);
+ double step_to_angle(int step, double center);
+
+// double calculate_variance(unsigned char *current_ptr,
+// int row_bytes,
+// int w,
+// int h,
+// int color_model);
+ double calculate_range(unsigned char *current_ptr,
+ int row_bytes,
+ int w,
+ int h,
+ int color_model);
+
+
+
+ AffineEngine *rotater;
// Pointer to downsampled frame before motion
VFrame *previous_frame;
// Pointer to downsampled frame after motion
// Downsampled frames
VFrame *downsampled_previous;
VFrame *downsampled_current;
+// rotated versions of current_frame
+ VFrame **rotated_current;
+// allocation of rotated_current array, a copy of angle_steps
+ int total_rotated;
// Test for identical frames before processing
// Faster to skip it if the frames are usually different
int test_match;
int skip;
+// macroblocks didn't have enough data
+ int failed;
// For single block
int block_x1;
int block_x2;
int block_y1;
int block_y2;
+ int scan_w;
+ int scan_h;
int scan_x1;
int scan_y1;
int scan_x2;
int scan_y2;
- int total_pixels;
- int total_steps;
- int edge_steps;
+ double scan_angle1, scan_angle2;
int y_steps;
int x_steps;
+ int angle_steps;
+// in deg
+ double angle_step;
int subpixel;
int horizontal_only;
int vertical_only;
int global_origin_x;
int global_origin_y;
-
- ArrayList<MotionScanCache*> cache;
- Mutex *cache_lock;
-// DownSampleServer *downsample;
+ int action_type;
+ int current_downsample;
+ int downsampled_w;
+ int downsampled_h;
+ int total_steps;
+ int do_motion;
+ int do_rotate;
+ int rotation_pass;
+// in deg
+ double rotation_center;
+ double rotation_range;
};
- add_subwindow(global = new MotionGlobal(plugin,
- this,
- x1,
- y));
+// add_subwindow(global = new MotionGlobal(plugin,
+// this,
+// x1,
+// y));
add_subwindow(rotate = new MotionRotate(plugin,
this,
// y,
// &plugin->config.rotation_block_h));
- y += 50;
- add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
- add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
- x1 + title->get_w() + 10,
- y,
- 80));
- global_search_positions->create_objects();
-
- add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
- add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
- x2 + title->get_w() + 10,
- y,
- 80));
- rotation_search_positions->create_objects();
+// y += 50;
+// add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
+// add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
+// x1 + title->get_w() + 10,
+// y,
+// 80));
+// global_search_positions->create_objects();
+//
+// add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
+// add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
+// x2 + title->get_w() + 10,
+// y,
+// 80));
+// rotation_search_positions->create_objects();
y += 50;
add_subwindow(title = new BC_Title(x, y, _("Translation direction:")));
this,
x + track_single->get_w() + title->get_w() + 20,
y));
- add_subwindow(addtrackedframeoffset = new AddTrackedFrameOffset(plugin,
- this,
- x + track_single->get_w() + title->get_w() + 20 + track_frame_number->get_w(),
- y));
-
y += 20;
add_subwindow(track_previous = new TrackPreviousFrame(plugin,
MIN_ROTATION,
MAX_ROTATION);
vectors->update(plugin->config.draw_vectors);
- global->update(plugin->config.global);
+// global->update(plugin->config.global);
rotate->update(plugin->config.rotate);
- addtrackedframeoffset->update(plugin->config.addtrackedframeoffset);
}
-GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin,
- int x,
- int y,
- int w)
- : BC_PopupMenu(x,
- y,
- w,
- "",
- 1)
-{
- this->plugin = plugin;
-}
-void GlobalSearchPositions::create_objects()
-{
- add_item(new BC_MenuItem("16"));
- add_item(new BC_MenuItem("32"));
- add_item(new BC_MenuItem("64"));
- add_item(new BC_MenuItem("128"));
- add_item(new BC_MenuItem("256"));
- add_item(new BC_MenuItem("512"));
- add_item(new BC_MenuItem("1024"));
- add_item(new BC_MenuItem("2048"));
- add_item(new BC_MenuItem("4096"));
- add_item(new BC_MenuItem("8192"));
- add_item(new BC_MenuItem("16384"));
- add_item(new BC_MenuItem("32768"));
- add_item(new BC_MenuItem("65536"));
- add_item(new BC_MenuItem("131072"));
- char string[BCTEXTLEN];
- sprintf(string, "%d", plugin->config.global_positions);
- set_text(string);
-}
-
-int GlobalSearchPositions::handle_event()
-{
- plugin->config.global_positions = atoi(get_text());
- plugin->send_configure_change();
- return 1;
-}
-
-
-
-
-
-
-
-RotationSearchPositions::RotationSearchPositions(MotionMain *plugin,
- int x,
- int y,
- int w)
- : BC_PopupMenu(x,
- y,
- w,
- "",
- 1)
-{
- this->plugin = plugin;
-}
-void RotationSearchPositions::create_objects()
-{
- add_item(new BC_MenuItem("4"));
- add_item(new BC_MenuItem("8"));
- add_item(new BC_MenuItem("16"));
- add_item(new BC_MenuItem("32"));
- char string[BCTEXTLEN];
- sprintf(string, "%d", plugin->config.rotate_positions);
- set_text(string);
-}
-
-int RotationSearchPositions::handle_event()
-{
- plugin->config.rotate_positions = atoi(get_text());
- plugin->send_configure_change();
- return 1;
-}
+// GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin,
+// int x,
+// int y,
+// int w)
+// : BC_PopupMenu(x,
+// y,
+// w,
+// "",
+// 1)
+// {
+// this->plugin = plugin;
+// }
+// void GlobalSearchPositions::create_objects()
+// {
+// add_item(new BC_MenuItem("16"));
+// add_item(new BC_MenuItem("32"));
+// add_item(new BC_MenuItem("64"));
+// add_item(new BC_MenuItem("128"));
+// add_item(new BC_MenuItem("256"));
+// add_item(new BC_MenuItem("512"));
+// add_item(new BC_MenuItem("1024"));
+// add_item(new BC_MenuItem("2048"));
+// add_item(new BC_MenuItem("4096"));
+// add_item(new BC_MenuItem("8192"));
+// add_item(new BC_MenuItem("16384"));
+// add_item(new BC_MenuItem("32768"));
+// add_item(new BC_MenuItem("65536"));
+// add_item(new BC_MenuItem("131072"));
+// char string[BCTEXTLEN];
+// sprintf(string, "%d", plugin->config.global_positions);
+// set_text(string);
+// }
+//
+// int GlobalSearchPositions::handle_event()
+// {
+// plugin->config.global_positions = atoi(get_text());
+// plugin->send_configure_change();
+// return 1;
+// }
+//
+//
+//
+//
+//
+//
+//
+// RotationSearchPositions::RotationSearchPositions(MotionMain *plugin,
+// int x,
+// int y,
+// int w)
+// : BC_PopupMenu(x,
+// y,
+// w,
+// "",
+// 1)
+// {
+// this->plugin = plugin;
+// }
+// void RotationSearchPositions::create_objects()
+// {
+// add_item(new BC_MenuItem("4"));
+// add_item(new BC_MenuItem("8"));
+// add_item(new BC_MenuItem("16"));
+// add_item(new BC_MenuItem("32"));
+// char string[BCTEXTLEN];
+// sprintf(string, "%d", plugin->config.rotate_positions);
+// set_text(string);
+// }
+//
+// int RotationSearchPositions::handle_event()
+// {
+// plugin->config.rotate_positions = atoi(get_text());
+// plugin->send_configure_change();
+// return 1;
+// }
-AddTrackedFrameOffset::AddTrackedFrameOffset(MotionMain *plugin,
- MotionWindow *gui,
- int x,
- int y)
- : BC_CheckBox(x,
- y,
- plugin->config.addtrackedframeoffset,
- _("Add (loaded) offset from tracked frame"))
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int AddTrackedFrameOffset::handle_event()
-{
- plugin->config.addtrackedframeoffset = get_value();
- plugin->send_configure_change();
- return 1;
-}
-
-
MotionRMagnitude::MotionRMagnitude(MotionMain *plugin,
int x,
int y)
-MotionGlobal::MotionGlobal(MotionMain *plugin,
- MotionWindow *gui,
- int x,
- int y)
- : BC_CheckBox(x,
- y,
- plugin->config.global,
- _("Track translation"))
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int MotionGlobal::handle_event()
-{
- plugin->config.global = get_value();
- plugin->send_configure_change();
- return 1;
-}
+// MotionGlobal::MotionGlobal(MotionMain *plugin,
+// MotionWindow *gui,
+// int x,
+// int y)
+// : BC_CheckBox(x,
+// y,
+// plugin->config.global,
+// _("Track translation"))
+// {
+// this->plugin = plugin;
+// this->gui = gui;
+// }
+//
+// int MotionGlobal::handle_event()
+// {
+// plugin->config.global = get_value();
+// plugin->send_configure_change();
+// return 1;
+// }
MotionRotate::MotionRotate(MotionMain *plugin,
MotionWindow *gui,
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
{
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
{
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;
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "affine.h"
+#include "bcsignals.h"
+#include "clip.h"
+#include "motionscan.h"
+#include "rotatescan.h"
+#include "motion.h"
+#include "mutex.h"
+#include "vframe.h"
+
+
+
+
+
+
+
+
+
+RotateScanPackage::RotateScanPackage()
+{
+}
+
+
+RotateScanUnit::RotateScanUnit(RotateScan *server, MotionMain *plugin)
+ : LoadClient(server)
+{
+ this->server = server;
+ this->plugin = plugin;
+ rotater = 0;
+ temp = 0;
+}
+
+RotateScanUnit::~RotateScanUnit()
+{
+ delete rotater;
+ delete temp;
+}
+
+void RotateScanUnit::process_package(LoadPackage *package)
+{
+ if(server->skip) return;
+ RotateScanPackage *pkg = (RotateScanPackage*)package;
+
+ if((pkg->difference = server->get_cache(pkg->angle)) < 0)
+ {
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+ int color_model = server->previous_frame->get_color_model();
+ int pixel_size = BC_CModels::calculate_pixelsize(color_model);
+ int row_bytes = server->previous_frame->get_bytes_per_line();
+
+ if(!rotater)
+ rotater = new AffineEngine(1, 1);
+ if(!temp) temp = new VFrame(0,
+ -1,
+ server->previous_frame->get_w(),
+ server->previous_frame->get_h(),
+ color_model,
+ -1);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+
+
+// Rotate original block size
+// rotater->set_viewport(server->block_x1,
+// server->block_y1,
+// server->block_x2 - server->block_x1,
+// server->block_y2 - server->block_y1);
+ rotater->set_in_viewport(server->block_x1,
+ server->block_y1,
+ server->block_x2 - server->block_x1,
+ server->block_y2 - server->block_y1);
+ rotater->set_out_viewport(server->block_x1,
+ server->block_y1,
+ server->block_x2 - server->block_x1,
+ server->block_y2 - server->block_y1);
+// rotater->set_pivot(server->block_x, server->block_y);
+ rotater->set_in_pivot(server->block_x, server->block_y);
+ rotater->set_out_pivot(server->block_x, server->block_y);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+ rotater->rotate(temp,
+ server->previous_frame,
+ pkg->angle);
+
+// Scan reduced block size
+//plugin->output_frame->copy_from(server->current_frame);
+//plugin->output_frame->copy_from(temp);
+// printf("RotateScanUnit::process_package %d %d %d %d %d\n",
+// __LINE__,
+// server->scan_x,
+// server->scan_y,
+// server->scan_w,
+// server->scan_h);
+// Clamp coordinates
+ int x1 = server->scan_x;
+ int y1 = server->scan_y;
+ int x2 = x1 + server->scan_w;
+ int y2 = y1 + server->scan_h;
+ x2 = MIN(temp->get_w(), x2);
+ y2 = MIN(temp->get_h(), y2);
+ x2 = MIN(server->current_frame->get_w(), x2);
+ y2 = MIN(server->current_frame->get_h(), y2);
+ x1 = MAX(0, x1);
+ y1 = MAX(0, y1);
+
+ if(x2 > x1 && y2 > y1)
+ {
+ pkg->difference = MotionScan::abs_diff(
+ temp->get_rows()[y1] + x1 * pixel_size,
+ server->current_frame->get_rows()[y1] + x1 * pixel_size,
+ row_bytes,
+ x2 - x1,
+ y2 - y1,
+ color_model);
+//printf("RotateScanUnit::process_package %d\n", __LINE__);
+ server->put_cache(pkg->angle, pkg->difference);
+ }
+
+// printf("RotateScanUnit::process_package 10 x=%d y=%d w=%d h=%d block_x=%d block_y=%d angle=%f scan_w=%d scan_h=%d diff=%lld\n",
+// server->block_x1,
+// server->block_y1,
+// server->block_x2 - server->block_x1,
+// server->block_y2 - server->block_y1,
+// server->block_x,
+// server->block_y,
+// pkg->angle,
+// server->scan_w,
+// server->scan_h,
+// pkg->difference);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+RotateScan::RotateScan(MotionMain *plugin,
+ int total_clients,
+ int total_packages)
+ : LoadServer(
+//1, 1
+total_clients, total_packages
+)
+{
+ this->plugin = plugin;
+ cache_lock = new Mutex("RotateScan::cache_lock");
+}
+
+
+RotateScan::~RotateScan()
+{
+ delete cache_lock;
+}
+
+void RotateScan::init_packages()
+{
+ for(int i = 0; i < get_total_packages(); i++)
+ {
+ RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
+ pkg->angle = i *
+ (scan_angle2 - scan_angle1) /
+ (total_steps - 1) +
+ scan_angle1;
+ }
+}
+
+LoadClient* RotateScan::new_client()
+{
+ return new RotateScanUnit(this, plugin);
+}
+
+LoadPackage* RotateScan::new_package()
+{
+ return new RotateScanPackage;
+}
+
+
+float RotateScan::scan_frame(VFrame *previous_frame,
+ VFrame *current_frame,
+ int block_x,
+ int block_y)
+{
+ skip = 0;
+ this->block_x = block_x;
+ this->block_y = block_y;
+
+//printf("RotateScan::scan_frame %d\n", __LINE__);
+ switch(plugin->config.tracking_type)
+ {
+ case MotionScan::NO_CALCULATE:
+ result = plugin->config.rotation_center;
+ skip = 1;
+ break;
+
+ case MotionScan::LOAD:
+ {
+ char string[BCTEXTLEN];
+ sprintf(string,
+ "%s%06ld",
+ ROTATION_FILE,
+ plugin->get_source_position());
+ FILE *input = fopen(string, "r");
+ if(input)
+ {
+ int temp = fscanf(input, "%f", &result);
+ fclose(input);
+ skip = 1;
+ }
+ else
+ {
+ perror("RotateScan::scan_frame LOAD");
+ }
+ break;
+ }
+ }
+
+
+
+
+
+
+
+
+ this->previous_frame = previous_frame;
+ this->current_frame = current_frame;
+ int w = current_frame->get_w();
+ int h = current_frame->get_h();
+ int block_w = w * plugin->config.global_block_w / 100;
+ int block_h = h * plugin->config.global_block_h / 100;
+
+ if(this->block_x - block_w / 2 < 0) block_w = this->block_x * 2;
+ if(this->block_y - block_h / 2 < 0) block_h = this->block_y * 2;
+ if(this->block_x + block_w / 2 > w) block_w = (w - this->block_x) * 2;
+ if(this->block_y + block_h / 2 > h) block_h = (h - this->block_y) * 2;
+
+ block_x1 = this->block_x - block_w / 2;
+ block_x2 = this->block_x + block_w / 2;
+ block_y1 = this->block_y - block_h / 2;
+ block_y2 = this->block_y + block_h / 2;
+
+
+// Calculate the maximum area available to scan after rotation.
+// Must be calculated from the starting range because of cache.
+// Get coords of rectangle after rotation.
+ double center_x = this->block_x;
+ double center_y = this->block_y;
+ double max_angle = plugin->config.rotation_range;
+ double base_angle1 = atan((float)block_h / block_w);
+ double base_angle2 = atan((float)block_w / block_h);
+ double target_angle1 = base_angle1 + max_angle * 2 * M_PI / 360;
+ double target_angle2 = base_angle2 + max_angle * 2 * M_PI / 360;
+ double radius = sqrt(block_w * block_w + block_h * block_h) / 2;
+ double x1 = center_x - cos(target_angle1) * radius;
+ double y1 = center_y - sin(target_angle1) * radius;
+ double x2 = center_x + sin(target_angle2) * radius;
+ double y2 = center_y - cos(target_angle2) * radius;
+ double x3 = center_x - sin(target_angle2) * radius;
+ double y3 = center_y + cos(target_angle2) * radius;
+
+// Track top edge to find greatest area.
+ double max_area1 = 0;
+ double max_x1 = 0;
+ double max_y1 = 0;
+ for(double x = x1; x < x2; x++)
+ {
+ double y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+ if(x >= center_x && x < block_x2 && y >= block_y1 && y < center_y)
+ {
+ double area = fabs(x - center_x) * fabs(y - center_y);
+ if(area > max_area1)
+ {
+ max_area1 = area;
+ max_x1 = x;
+ max_y1 = y;
+ }
+ }
+ }
+
+// Track left edge to find greatest area.
+ double max_area2 = 0;
+ double max_x2 = 0;
+ double max_y2 = 0;
+ for(double y = y1; y < y3; y++)
+ {
+ double x = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
+ if(x >= block_x1 && x < center_x && y >= block_y1 && y < center_y)
+ {
+ double area = fabs(x - center_x) * fabs(y - center_y);
+ if(area > max_area2)
+ {
+ max_area2 = area;
+ max_x2 = x;
+ max_y2 = y;
+ }
+ }
+ }
+
+ double max_x, max_y;
+ max_x = max_x2;
+ max_y = max_y1;
+
+// Get reduced scan coords
+ scan_w = (int)(fabs(max_x - center_x) * 2);
+ scan_h = (int)(fabs(max_y - center_y) * 2);
+ scan_x = (int)(center_x - scan_w / 2);
+ scan_y = (int)(center_y - scan_h / 2);
+// printf("RotateScan::scan_frame center=%d,%d scan=%d,%d %dx%d\n",
+// this->block_x, this->block_y, scan_x, scan_y, scan_w, scan_h);
+// printf(" angle_range=%f block= %d,%d,%d,%d\n", max_angle, block_x1, block_y1, block_x2, block_y2);
+
+// Determine min angle from size of block
+ double angle1 = atan((double)block_h / block_w);
+ double angle2 = atan((double)(block_h - 1) / (block_w + 1));
+ double min_angle = fabs(angle2 - angle1) / OVERSAMPLE;
+ min_angle = MAX(min_angle, MIN_ANGLE);
+
+//printf("RotateScan::scan_frame %d min_angle=%f\n", __LINE__, min_angle * 360 / 2 / M_PI);
+
+ cache.remove_all_objects();
+
+
+ if(!skip)
+ {
+ if(previous_frame->data_matches(current_frame))
+ {
+//printf("RotateScan::scan_frame: frames match. Skipping.\n");
+ result = plugin->config.rotation_center;
+ skip = 1;
+ }
+ }
+
+ if(!skip)
+ {
+// Initial search range
+ float angle_range = max_angle;
+ result = plugin->config.rotation_center;
+ total_steps = plugin->config.rotate_positions;
+
+
+ while(angle_range >= min_angle * total_steps)
+ {
+ scan_angle1 = result - angle_range;
+ scan_angle2 = result + angle_range;
+
+
+ set_package_count(total_steps);
+//set_package_count(1);
+ process_packages();
+
+ int64_t min_difference = -1;
+ for(int i = 0; i < get_total_packages(); i++)
+ {
+ RotateScanPackage *pkg = (RotateScanPackage*)get_package(i);
+ if(pkg->difference < min_difference || min_difference == -1)
+ {
+ min_difference = pkg->difference;
+ result = pkg->angle;
+ }
+//break;
+ }
+
+ angle_range /= 2;
+
+//break;
+ }
+ }
+
+//printf("RotateScan::scan_frame %d\n", __LINE__);
+
+ if(!skip && plugin->config.tracking_type == MotionScan::SAVE)
+ {
+ char string[BCTEXTLEN];
+ sprintf(string,
+ "%s%06ld",
+ ROTATION_FILE,
+ plugin->get_source_position());
+ FILE *output = fopen(string, "w");
+ if(output)
+ {
+ fprintf(output, "%f\n", result);
+ fclose(output);
+ }
+ else
+ {
+ perror("RotateScan::scan_frame SAVE");
+ }
+ }
+
+//printf("RotateScan::scan_frame %d angle=%f\n", __LINE__, result);
+
+
+
+ return result;
+}
+
+int64_t RotateScan::get_cache(float angle)
+{
+ int64_t result = -1;
+ cache_lock->lock("RotateScan::get_cache");
+ for(int i = 0; i < cache.total; i++)
+ {
+ RotateScanCache *ptr = cache.values[i];
+ if(fabs(ptr->angle - angle) <= MIN_ANGLE)
+ {
+ result = ptr->difference;
+ break;
+ }
+ }
+ cache_lock->unlock();
+ return result;
+}
+
+void RotateScan::put_cache(float angle, int64_t difference)
+{
+ RotateScanCache *ptr = new RotateScanCache(angle, difference);
+ cache_lock->lock("RotateScan::put_cache");
+ cache.append(ptr);
+ cache_lock->unlock();
+}
+
+
+
+
+
+
+
+
+
+RotateScanCache::RotateScanCache(float angle, int64_t difference)
+{
+ this->angle = angle;
+ this->difference = difference;
+}
+
+
+
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+
+
+#ifndef ROTATESCAN_H
+#define ROTATESCAN_H
+
+
+
+#include "affine.inc"
+#include "loadbalance.h"
+#include "motion.inc"
+#include "vframe.inc"
+#include <stdint.h>
+
+class RotateScan;
+
+
+class RotateScanPackage : public LoadPackage
+{
+public:
+ RotateScanPackage();
+ float angle;
+ int64_t difference;
+};
+
+class RotateScanCache
+{
+public:
+ RotateScanCache(float angle, int64_t difference);
+ float angle;
+ int64_t difference;
+};
+
+class RotateScanUnit : public LoadClient
+{
+public:
+ RotateScanUnit(RotateScan *server, MotionMain *plugin);
+ ~RotateScanUnit();
+
+ void process_package(LoadPackage *package);
+
+ RotateScan *server;
+ MotionMain *plugin;
+ AffineEngine *rotater;
+ VFrame *temp;
+};
+
+class RotateScan : public LoadServer
+{
+public:
+ RotateScan(MotionMain *plugin,
+ int total_clients,
+ int total_packages);
+ ~RotateScan();
+
+ friend class RotateScanUnit;
+
+ void init_packages();
+ LoadClient* new_client();
+ LoadPackage* new_package();
+
+// Invoke the motion engine for a search
+// Frame before rotation
+ float scan_frame(VFrame *previous_frame,
+// Frame after rotation
+ VFrame *current_frame,
+// Pivot
+ int block_x,
+ int block_y);
+ int64_t get_cache(float angle);
+ void put_cache(float angle, int64_t difference);
+
+
+// Angle result
+ float result;
+
+private:
+ VFrame *previous_frame;
+// Frame after motion
+ VFrame *current_frame;
+
+ MotionMain *plugin;
+ int skip;
+
+// Pivot
+ int block_x;
+ int block_y;
+// Block to rotate
+ int block_x1;
+ int block_x2;
+ int block_y1;
+ int block_y2;
+// Area to compare
+ int scan_x;
+ int scan_y;
+ int scan_w;
+ int scan_h;
+// Range of angles to compare
+ float scan_angle1, scan_angle2;
+ int total_steps;
+
+ ArrayList<RotateScanCache*> cache;
+ Mutex *cache_lock;
+};
+
+
+
+
+
+#endif
+
+
+
+
+
--- /dev/null
+#ifndef ROTATESCAN_INC
+#define ROTATESCAN_INC
+
+
+class RotateScan;
+
+
+#endif
+
+
+
+
/*
* CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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;
/*
* CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
+ * Copyright (C) 2008-2016 Adam Williams <broadcast at earthling dot net>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
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);
~ReframeRTWindow();
void create_objects();
ReframeRT *plugin;
- ReframeRTScale *scale;
+ ReframeRTNum *num;
+ ReframeRTDenom *denom;
ReframeRTStretch *stretch;
ReframeRTDownsample *downsample;
ReframeRTInterpolate *interpolate;
ReframeRTConfig::ReframeRTConfig()
{
- scale = 1.0;
+ num = 1.0;
+ denom = 1.0;
stretch = 0;
interp = 0;
optic_flow = 1;
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;
}
{
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;
}
ReframeRTWindow::ReframeRTWindow(ReframeRT *plugin)
- : PluginClientWindow(plugin, 230, 160, 230, 160, 0)
+ : PluginClientWindow(plugin, 230, 190, 230, 190, 0)
{
this->plugin = plugin;
}
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();
}
-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,
// 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__,
// 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();
{
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);
}
{
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);
/*
* CINELERRA
- * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2010-2016 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
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,
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;
}
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();
}
-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,
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;
}
}
source_start = (int64_t)((start_position - prev_position) *
- config.scale) + prev_position;
+ config.num / config.denom) + prev_position;
resample->reset();
need_reconfigure = 0;
resample->resample(buffer,
size,
- (int)1000000,
- (int)(1000000 / config.scale),
+ (int)(65536 * config.num),
+ (int)(65536 * config.denom),
start_position,
get_direction());
// 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();
{
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);
}
}
}
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();
}
}
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);
void create_objects();
ResampleRT *plugin;
- ResampleRTScale *scale;
+ ResampleRTNum *num;
+ ResampleRTDenom *denom;
};
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