result = 0;
beep = 0;
to_proxy = 0;
+ renderer = 0;
}
ConvertRender::~ConvertRender()
{
+ if( running() ) {
+ canceled = 1;
+ if( renderer )
+ renderer->set_result(1);
+ cancel();
+ join();
+ }
+ delete renderer;
delete [] suffix;
delete progress;
delete counter_lock;
Asset *needed_copy = needed_copies[i];
EDL *edl = convert_edl(mwindow->edl, orig_idxbl);
double length = get_length(orig_idxbl);
- ConvertPackageRenderer renderer(this);
- renderer.initialize(mwindow, edl, mwindow->preferences, needed_copy);
+ renderer = new ConvertPackageRenderer(this);
+ renderer->initialize(mwindow, edl, mwindow->preferences, needed_copy);
PackageDispatcher dispatcher;
dispatcher.create_packages(mwindow, edl, mwindow->preferences,
SINGLE_PASS, needed_copy, 0, length, 0);
RenderPackage *package = dispatcher.get_package(0);
- if( !renderer.render_package(package) ) {
+ if( !renderer->render_package(package) ) {
Asset *asset = mwindow->edl->assets->update(needed_copy);
mwindow->mainindexes->add_indexable(asset);
mwindow->mainindexes->start_build();
}
else
failed = 1;
+ delete renderer; renderer = 0;
edl->remove_user();
}
MainProgressBar *progress;
ConvertProgress *convert_progress;
Timer *progress_timer;
+ ConvertPackageRenderer *renderer;
Mutex *counter_lock;
int total_rendered, remove_originals;
{
public:
ConvertPackageRenderer(ConvertRender *render);
- ~ConvertPackageRenderer();
+ virtual ~ConvertPackageRenderer();
int get_master();
int get_result();
lock_window("RecordGUIMonitorVideo::handle_event");
record->video_window_open = 1;
}
+ else {
+ unlock_window();
+ BC_Window *window = record->record_monitor->window;
+ window->lock_window("RecordGUIMonitorVideo::handle_event");
+ window->hide_window();
+ window->flush();
+ window->unlock_window();
+ lock_window("RecordGUIMonitorVideo::handle_event");
+ record->video_window_open = 0;
+ }
return 1;
}
// Make positions based on requested frame rate.
int64_t position = Units::to_int64((double)pos * frame_rate / edl_rate);
- int64_t max_position;
+ int64_t video_length;
int asset_w, asset_h;
if( file ) {
asset_w = current_edit->asset->width;
asset_h = current_edit->asset->height;
- max_position = Units::to_int64((double)file->get_video_length() *
- frame_rate / current_edit->asset->frame_rate - 1);
+ video_length = file->get_video_length();
}
else {
asset_w = nested_edl->session->output_w;
asset_h = nested_edl->session->output_h;
- max_position = Units::to_int64(nested_edl->tracks->total_length() *
- frame_rate - 1);
+ video_length = nested_edl->tracks->total_length();
}
- if( max_position < 0 ) max_position = 0;
-// if we hit the end of stream, freeze at last frame
- CLAMP(position, 0, max_position);
VFrame *&input = commonrender ?
((VRender*)commonrender)->input_temp : // Realtime playback
curr_pos += current_edit->startsource;
int64_t norm_pos = Units::to_int64((double)curr_pos *
current_edit->asset->frame_rate / edl_rate);
+ if( norm_pos < 0 || video_length < 0 )
+ norm_pos = 0;
+ else if( norm_pos >= video_length )
+ norm_pos = video_length-1;
if( first_frame ) {
if( file->get_cache_frame(input, norm_pos) )
break; // if inside a cache run
int64_t normalized_position = Units::to_int64((double)position *
current_edit->asset->frame_rate / frame_rate);
+ if( normalized_position < 0 || video_length < 0 )
+ normalized_position = 0;
+ else if( normalized_position >= video_length )
+ normalized_position = video_length-1;
//printf("VModule::import_frame %d %lld %lld\n", __LINE__, position, normalized_position);
file->set_layer(current_edit->channel);
file->set_video_position(normalized_position, 0);
{
if( viewing ) viewing->stop_audio();
delete view_win; view_win = 0;
- if( (viewing=vicon) != 0 ) {
+ VFrame *vfrm;
+ if( (viewing=vicon) != 0 && (vfrm=viewing->frame()) != 0 ) {
view_win = new_view_window(0);
- view_win->draw_vframe(viewing->frame());
+ view_win->draw_vframe(vfrm);
view_win->flash(0);
view_win->show_window();
if( do_audio ) vicon->start_audio();
int VIconThread::zoom_scale(int dir)
{
- if( !viewing || !view_win ) return 0;
+ VFrame *vfrm;
+ if( !viewing || !view_win || !(vfrm=viewing->frame()) ) return 0;
int view_h = this->view_h;
view_h += dir*view_h/10 + dir;
bclamp(view_h, 16,512);
this->view_h = view_h;
this->view_w = view_h * vw/vh;
new_view_window(view_win);
- view_win->draw_vframe(viewing->frame());
+ view_win->draw_vframe(vfrm);
view_win->flash(1);
return 1;
}
int draw_img = visible(vicon, x, y);
int draw_win = view_win && viewing == vicon ? 1 : 0;
if( !draw_img && !draw_win ) return 0;
- if( !vicon->frame() ) return 0;
+ VFrame *vfrm = vicon->frame();
+ if( !vfrm ) return 0;
if( draw_img ) {
vicon->draw_vframe(this, wdw, x, y);
img_dirty = 1;
}
if( draw_win ) {
- view_win->draw_vframe(vicon->frame());
+ view_win->draw_vframe(vfrm);
win_dirty = 1;
}
return 1;
swapframes \
threshold \
timeavg \
+ timeblur \
timefront \
titler \
tracer \
synthesizer \
threshold \
timeavg \
+ timeblur \
timefront \
timestretch \
timestretchrt \
: PluginVClient(server)
{
engine = 0;
- stripe_engine = 0;
for( int i=0; i<HISTOGRAM_MODES; ++i ) {
- lookup[i] = 0;
- accum[i] = 0;
- preview_lookup[i] = 0;
+ lookup[i] = new int[0x10000];
+ preview_lookup[i] = new int[0x10000];
+ accum[i] = new int64_t[HISTOGRAM_SLOTS];
+ bzero(accum[i], sizeof(int64_t)*HISTOGRAM_SLOTS);
}
current_point = -1;
mode = HISTOGRAM_VALUE;
+ last_position = -1;
+ need_reconfigure = 1;
+ sum_frames = 0;
+ frames = 1;
dragging_point = 0;
input = 0;
output = 0;
w = 440;
h = 500;
parade = 0;
- fframe = 0;
- last_frames = 0;
- last_position = -1;
}
HistogramMain::~HistogramMain()
for( int i=0; i<HISTOGRAM_MODES; ++i ) {
delete [] lookup[i];
- delete [] accum[i];
delete [] preview_lookup[i];
+ delete [] accum[i];
}
delete engine;
- delete stripe_engine;
- delete fframe;
}
const char* HistogramMain::plugin_title() { return N_("Histogram"); }
void HistogramMain::render_gui(void *data)
{
- input = (VFrame*)data;
- if( thread ) {
-// Process just the RGB values to determine the automatic points or
-// all the points if manual
- if( !config.automatic ) {
-// Generate curves for value histogram
-// Lock out changes to curves
- ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
- tabulate_curve(HISTOGRAM_RED, 0);
- tabulate_curve(HISTOGRAM_GREEN, 0);
- tabulate_curve(HISTOGRAM_BLUE, 0);
- tabulate_curve(preview_lookup, HISTOGRAM_RED, 0x10000, 0);
- tabulate_curve(preview_lookup, HISTOGRAM_GREEN, 0x10000, 0);
- tabulate_curve(preview_lookup, HISTOGRAM_BLUE, 0x10000, 0);
- ((HistogramWindow*)thread->window)->unlock_window();
- }
-
- calculate_histogram(input, !config.automatic);
-
- if( config.automatic ) {
- calculate_automatic(input);
-// Generate curves for value histogram
-// Lock out changes to curves
- ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
- tabulate_curve(HISTOGRAM_RED, 0);
- tabulate_curve(HISTOGRAM_GREEN, 0);
- tabulate_curve(HISTOGRAM_BLUE, 0);
- tabulate_curve(preview_lookup, HISTOGRAM_RED, 0x10000, 0);
- tabulate_curve(preview_lookup, HISTOGRAM_GREEN, 0x10000, 0);
- tabulate_curve(preview_lookup, HISTOGRAM_BLUE, 0x10000, 0);
- ((HistogramWindow*)thread->window)->unlock_window();
-// Need a second pass to get the luminance values.
- calculate_histogram(input, 1);
- }
-
- ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 2");
-// Always draw the histogram but don't update widgets if automatic
- ((HistogramWindow*)thread->window)->update(1,
- config.automatic && mode != HISTOGRAM_VALUE,
- config.automatic && mode != HISTOGRAM_VALUE,
- 0);
-
- ((HistogramWindow*)thread->window)->unlock_window();
+ if( !thread ) return;
+ HistogramWindow *window = (HistogramWindow*)thread->window;
+ HistogramMain *plugin = (HistogramMain*)data;
+//update gui client instance, needed for drawing
+ for( int i=0; i<HISTOGRAM_MODES; ++i ) {
+ config.low_input[i] = plugin->config.low_input[i];
+ config.high_input[i] = plugin->config.high_input[i];
+ memcpy(accum[i], plugin->accum[i], HISTOGRAM_SLOTS*sizeof(*accum));
}
+ window->lock_window("HistogramMain::render_gui 2");
+// draw all if reconfigure
+ int reconfig = plugin->need_reconfigure;
+// Always draw the histogram but don't update widgets if automatic
+ int auto_rgb = reconfig ? 1 : config.automatic && mode != HISTOGRAM_VALUE ? 1 : 0;
+ window->update(1, auto_rgb, auto_rgb, reconfig);
+ window->unlock_window();
}
void HistogramMain::update_gui()
void HistogramMain::save_data(KeyFrame *keyframe)
{
FileXML output;
-
// cause data to be stored directly in text
output.set_shared_output(keyframe->xbuf);
output.tag.set_title("HISTOGRAM");
output.tag.set_property("AUTOMATIC", config.automatic);
output.tag.set_property("THRESHOLD", config.threshold);
output.tag.set_property("PLOT", config.plot);
+ output.tag.set_property("SUM_FRAMES", config.sum_frames);
output.tag.set_property("SPLIT", config.split);
- output.tag.set_property("FRAMES", config.frames);
output.tag.set_property("LOG_SLIDER", config.log_slider);
output.tag.set_property("W", w);
output.tag.set_property("H", h);
config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
config.plot = input.tag.get_property("PLOT", config.plot);
+ config.sum_frames = input.tag.get_property("SUM_FRAMES", config.sum_frames);
config.split = input.tag.get_property("SPLIT", config.split);
- config.frames = input.tag.get_property("FRAMES", config.frames);
config.log_slider = input.tag.get_property("LOG_SLIDER", config.log_slider);
if( is_defaults() ) {
if( cpus > smps ) cpus = smps;
engine = new HistogramEngine(this, cpus, cpus);
}
- if( !accum[0] ) {
- for( int i=0; i<HISTOGRAM_MODES; ++i )
- accum[i] = new int[HISTOGRAM_SLOTS];
- }
engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
+ int k = 0;
HistogramUnit *unit = (HistogramUnit*)engine->get_client(0);
- for( int i=0; i<HISTOGRAM_MODES; ++i )
- memcpy(accum[i], unit->accum[i], sizeof(int)*HISTOGRAM_SLOTS);
+ if( !sum_frames ) {
+ frames = 0;
+ for( int i=0; i<HISTOGRAM_MODES; ++i )
+ memcpy(accum[i], unit->accum[i], sizeof(int64_t)*HISTOGRAM_SLOTS);
+ k = 1;
+ }
- for( int i=1,n=engine->get_total_clients(); i<n; ++i ) {
+ for( int i=k,n=engine->get_total_clients(); i<n; ++i ) {
unit = (HistogramUnit*)engine->get_client(i);
for( int j=0; j<HISTOGRAM_MODES; ++j ) {
- int *in = unit->accum[j], *out = accum[j];
+ int64_t *in = unit->accum[j], *out = accum[j];
for( int k=HISTOGRAM_SLOTS; --k>=0; ) *out++ += *in++;
}
}
accum[i][0] = 0;
accum[i][HISTOGRAM_SLOTS - 1] = 0;
}
+ ++frames;
}
// Do each channel
for( int i=0; i<3; ++i ) {
- int *accum = this->accum[i];
- int pixels = data->get_w() * data->get_h();
+ int64_t *accum = this->accum[i];
+ int64_t sz = data->get_w() * data->get_h();
+ int64_t pixels = sz * frames;
float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
int threshold = (int)(white_fraction * pixels);
float min_level = 0.0, max_level = 1.0;
// Get histogram slot above threshold of pixels
- for( int j=0, total=0; j<HISTOGRAM_SLOTS; ++j ) {
+ int64_t total = 0;
+ for( int j=0; j<HISTOGRAM_SLOTS; ++j ) {
total += accum[j];
if( total >= threshold ) {
max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
}
}
-// Get slot below 99% of pixels
- for( int j=HISTOGRAM_SLOTS, total=0; --j> 0; ) {
+// Get histogram slot below threshold of pixels
+ total = 0;
+ for( int j=HISTOGRAM_SLOTS; --j> 0; ) {
total += accum[j];
if( total >= threshold ) {
min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
int64_t start_position,
double frame_rate)
{
- int need_reconfigure = load_configuration();
+ need_reconfigure = load_configuration();
int use_opengl = calculate_use_opengl();
-
+ sum_frames = last_position == start_position ? config.sum_frames : 0;
+ last_position = get_direction() == PLAY_FORWARD ?
+ start_position+1 : start_position-1;
this->input = frame;
this->output = frame;
int cpus = input->get_w() * input->get_h() / 0x80000 + 2;
int smps = get_project_smp();
if( cpus > smps ) cpus = smps;
- if( !engine ) {
+ if( !engine )
engine = new HistogramEngine(this, cpus, cpus);
+ read_frame(frame, 0, start_position, frame_rate, use_opengl);
+ if( config.automatic )
+ calculate_automatic(frame);
+ if( config.plot ) {
+// Generate curves for value histogram
+ tabulate_curve(lookup, 0);
+ tabulate_curve(preview_lookup, 0, 0x10000);
+// Need to get the luminance values.
+ calculate_histogram(input, 1);
+ send_render_gui(this);
}
- int frames = config.frames;
- MWindow *mwindow = server->mwindow;
- if( frames > 1 && (!mwindow || // dont scan during SELECT_REGION
- mwindow->session->current_operation != SELECT_REGION ||
- mwindow->edl->local_session->get_selectionstart() ==
- mwindow->edl->local_session->get_selectionend() ) ) {
- if( !stripe_engine )
- stripe_engine = new HistStripeEngine(this, cpus, cpus);
- int fw = frame->get_w(), fh =frame->get_h();
- new_temp(fw, fh, BC_RGB_FLOAT);
- MWindow *mwindow = server->mwindow;
- if( (mwindow && mwindow->session->current_operation == SELECT_REGION) ||
- ( last_frames == frames && last_position-1 == start_position &&
- fframe && fframe->get_w() == fw && fframe->get_h() == fh ) ) {
- read_frame(temp, 0, start_position, frame_rate, use_opengl);
- stripe_engine->process_packages(ADD_FFRM);
- frame->transfer_from(temp);
- }
- else if( last_frames != frames || last_position != start_position ||
- !fframe || fframe->get_w() != fw || fframe->get_h() != fh ) {
- last_frames = frames;
- last_position = start_position;
- VFrame::get_temp(fframe, fw, fh, BC_RGB_FLOAT);
- read_frame(fframe, 0, start_position+1, frame_rate, use_opengl);
- BC_ProgressBox *progress = 0;
- const char *progress_title = _("Histogram: scanning\n");
- Timer timer;
- for( int i=2; i<frames; ++i ) {
- read_frame(temp, 0, start_position+i, frame_rate, use_opengl);
- stripe_engine->process_packages(ADD_TEMP);
- if( !progress && gui_open() && frames > 2*frame_rate ) {
- progress = new BC_ProgressBox(-1, -1, progress_title, frames);
- progress->start();
- }
- if( progress && timer.get_difference() > 100 ) {
- timer.update();
- progress->update(i, 1);
- char string[BCTEXTLEN];
- sprintf(string, "%sframe: %d", progress_title, i);
- progress->update_title(string, 1);
- if( progress->is_cancelled() ) break;
- }
- if( progress && !gui_open() ) {
- progress->stop_progress();
- delete progress; progress = 0;
- }
- }
- read_frame(temp, 0, start_position, frame_rate, use_opengl);
- stripe_engine->process_packages(ADD_FFRMS);
- frame->transfer_from(temp);
- if( progress ) {
- progress->stop_progress();
- delete progress;
- }
- ++last_position;
- }
- else {
- read_frame(temp, 0, start_position+frames-1, frame_rate, use_opengl);
- stripe_engine->process_packages(ADD_TEMPS);
- frame->transfer_from(fframe);
- read_frame(temp, 0, start_position, frame_rate, use_opengl);
- stripe_engine->process_packages(SUB_TEMPS);
- ++last_position;
- }
- }
- else
- read_frame(frame, 0, start_position, frame_rate, use_opengl);
-// if to plot histogram
- if(config.plot) send_render_gui(frame);
-
-// Generate tables here. The same table is used by many packages to render
-// each horizontal stripe. Need to cover the entire output range in each
-// table to avoid green borders
-
-
- if( need_reconfigure || !lookup[0] || config.automatic ) {
+ if( need_reconfigure || config.automatic || config.plot ) {
// Calculate new curves
- if( config.automatic )
- calculate_automatic(input);
// Generate transfer tables with value function for integer colormodels.
- for( int i=0; i<3; ++i )
- tabulate_curve(i, 1);
+ tabulate_curve(lookup, 1);
}
// Apply histogram in hardware
return 0;
}
-void HistogramMain::tabulate_curve(int **table, int idx, int len, int use_value)
+void HistogramMain::tabulate_curve(int **table, int idx, int use_value, int len)
{
- if( !table[idx] ) // must use max demand here
- table[idx] = new int[0x10000];
- int *curve = table[idx], len1 = len-1;
+ int len1 = len - 1;
+ int *curve = table[idx];
for( int i=0; i<len; ++i ) {
curve[i] = calculate_level((float)i/len1, idx, use_value) * len1;
CLAMP(curve[i], 0, len1);
}
}
-void HistogramMain::tabulate_curve(int idx, int use_value)
+void HistogramMain::tabulate_curve(int **table, int use_value, int len)
{
// uint8 rgb is 8 bit, all others are converted to 16 bit RGB
- int color_model = input->get_color_model();
- int lookup_len = color_model == BC_RGB888 ||
- color_model == BC_RGBA8888 ? 0x100 : 0x10000;
- tabulate_curve(lookup, idx, lookup_len, use_value);
+ if( len < 0 ) {
+ int color_model = input->get_color_model();
+ len = color_model == BC_RGB888 || color_model == BC_RGBA8888 ?
+ 0x100 : 0x10000;
+ }
+ for( int i=0; i<3; ++i )
+ tabulate_curve(table, i, use_value, len);
}
int HistogramMain::handle_opengl()
}
-HistStripePackage::HistStripePackage()
- : LoadPackage()
-{
-}
-
-HistStripeUnit::HistStripeUnit(HistStripeEngine *server, HistogramMain *plugin)
- : LoadClient(server)
-{
- this->plugin = plugin;
- this->server = server;
-}
-
-void HistStripeUnit::process_package(LoadPackage *package)
-{
- HistStripePackage *pkg = (HistStripePackage*)package;
- int frames = plugin->config.frames;
- float scale = 1. / frames;
- int iy0 = pkg->y0, iy1 = pkg->y1;
- int fw = plugin->fframe->get_w();
- uint8_t **frows = plugin->fframe->get_rows();
- uint8_t **trows = plugin->temp->get_rows();
- switch( server->operation ) {
- case ADD_TEMP: // add temp to fframe
- for( int iy=iy0; iy<iy1; ++iy ) {
- float *trow = (float *)trows[iy];
- float *frow = (float *)frows[iy];
- for( int ix=0; ix<fw; ++ix ) {
- *frow++ += *trow++;
- *frow++ += *trow++;
- *frow++ += *trow++;
- }
- }
- break;
- case ADD_FFRM: // add fframe to scaled temp
- for( int iy=iy0; iy<iy1; ++iy ) {
- float *trow = (float *)trows[iy];
- float *frow = (float *)frows[iy];
- for( int ix=0; ix<fw; ++ix ) {
- *trow = *trow * scale + *frow++; ++trow;
- *trow = *trow * scale + *frow++; ++trow;
- *trow = *trow * scale + *frow++; ++trow;
- }
- }
- break;
- case ADD_FFRMS: // add fframe to temp, scale temp, scale fframe
- for( int iy=iy0; iy<iy1; ++iy ) {
- float *trow = (float *)trows[iy];
- float *frow = (float *)frows[iy];
- for( int ix=0; ix<fw; ++ix ) {
- *trow += *frow; *trow++ *= scale; *frow++ *= scale;
- *trow += *frow; *trow++ *= scale; *frow++ *= scale;
- *trow += *frow; *trow++ *= scale; *frow++ *= scale;
- }
- }
- break;
- case ADD_TEMPS: // add scaled temp to fframe
- for( int iy=iy0; iy<iy1; ++iy ) {
- float *trow = (float *)trows[iy];
- float *frow = (float *)frows[iy];
- for( int ix=0; ix<fw; ++ix ) {
- *frow++ += *trow++ * scale;
- *frow++ += *trow++ * scale;
- *frow++ += *trow++ * scale;
- }
- }
- break;
- case SUB_TEMPS: // sub scaled temp from frame
- for( int iy=iy0; iy<iy1; ++iy ) {
- float *trow = (float *)trows[iy];
- float *frow = (float *)frows[iy];
- for( int ix=0; ix<fw; ++ix ) {
- *frow++ -= *trow++ * scale;
- *frow++ -= *trow++ * scale;
- *frow++ -= *trow++ * scale;
- }
- }
- break;
- }
-}
-
-HistStripeEngine::HistStripeEngine(HistogramMain *plugin,
- int total_clients, int total_packages)
- : LoadServer(total_clients, total_packages)
-{
- this->plugin = plugin;
-}
-void HistStripeEngine::init_packages()
-{
- int ih = plugin->input->get_h(), iy0 = 0;
- for( int i=0,n=get_total_packages(); i<n; ) {
- HistStripePackage *pkg = (HistStripePackage*)get_package(i);
- int iy1 = (ih * ++i) / n;
- pkg->y0 = iy0; pkg->y1 = iy1;
- iy0 = iy1;
- }
-}
-
-LoadClient* HistStripeEngine::new_client()
-{
- return new HistStripeUnit(this, plugin);
-}
-
-LoadPackage* HistStripeEngine::new_package()
-{
- return new HistStripePackage();
-}
-
-void HistStripeEngine::process_packages(int operation)
-{
- this->operation = operation;
- LoadServer::process_packages();
-}
-
-
-
HistogramPackage::HistogramPackage()
: LoadPackage()
{
this->plugin = plugin;
this->server = server;
for(int i = 0; i < HISTOGRAM_MODES; i++)
- accum[i] = new int[HISTOGRAM_SLOTS];
+ accum[i] = new int64_t[HISTOGRAM_SLOTS];
}
HistogramUnit::~HistogramUnit()
b_out = preview_b[bclip(b, 0, 0xffff)]; \
/* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
/* Value takes the maximum of the output RGB values */ \
- v = MAX(r_out, g_out); v = MAX(v, b_out); \
+ int v = MAX(r_out, g_out); v = MAX(v, b_out); \
++accum_v[bclip(v -= hmin, 0, slots1)]; \
} \
\
VFrame *data = server->data;
int w = data->get_w();
//int h = data->get_h();
- int *accum_r = accum[HISTOGRAM_RED];
- int *accum_g = accum[HISTOGRAM_GREEN];
- int *accum_b = accum[HISTOGRAM_BLUE];
- int *accum_v = accum[HISTOGRAM_VALUE];
+ int64_t *accum_r = accum[HISTOGRAM_RED];
+ int64_t *accum_g = accum[HISTOGRAM_GREEN];
+ int64_t *accum_b = accum[HISTOGRAM_BLUE];
+ int64_t *accum_v = accum[HISTOGRAM_VALUE];
int32_t r, g, b, y, u, v;
int r_out, g_out, b_out;
int *preview_r = plugin->preview_lookup[HISTOGRAM_RED];
for( int i=0,n=get_total_clients(); i<n; ++i ) {
HistogramUnit *unit = (HistogramUnit*)get_client(i);
for( int j=0; j<HISTOGRAM_MODES; ++j )
- bzero(unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
+ bzero(unit->accum[j], sizeof(int64_t) * HISTOGRAM_SLOTS);
}
}
void read_data(KeyFrame *keyframe);
void update_gui();
void render_gui(void *data);
+ void do_render_gui(HistogramWindow *gui);
int calculate_use_opengl();
int handle_opengl();
// Value is only calculated for preview.
void calculate_histogram(VFrame *data, int do_value);
// Calculate the linear, smoothed, lookup curves
- void tabulate_curve(int **table, int idx, int len, int use_value);
- void tabulate_curve(int idx, int use_value);
+ void tabulate_curve(int **table, int idx, int use_value, int len);
+ void tabulate_curve(int **table, int use_value, int len=-1);
VFrame *input, *output;
HistogramEngine *engine;
- HistStripeEngine *stripe_engine;
+ int need_reconfigure;
int *lookup[HISTOGRAM_MODES];
// No value applied to this
int *preview_lookup[HISTOGRAM_MODES];
- int *accum[HISTOGRAM_MODES];
+ int64_t *accum[HISTOGRAM_MODES];
// Input point being dragged or edited
int current_point;
// Current channel being viewed
int point_y_offset;
int w, h;
int parade;
- VFrame *fframe;
int64_t last_position;
- int last_frames;
-};
-
-enum { ADD_TEMP, ADD_FFRM, ADD_FFRMS, ADD_TEMPS, SUB_TEMPS };
-
-class HistStripePackage : public LoadPackage
-{
-public:
- HistStripePackage();
- int y0, y1;
-};
-
-class HistStripeUnit : public LoadClient
-{
-public:
- HistStripeUnit(HistStripeEngine *server, HistogramMain *plugin);
- void process_package(LoadPackage *package);
- HistStripeEngine *server;
- HistogramMain *plugin;
-};
-
-class HistStripeEngine : public LoadServer
-{
-public:
- HistStripeEngine(HistogramMain *plugin, int total_clients, int total_packages);
- void process_packages(int operation);
- void init_packages();
- LoadClient *new_client();
- LoadPackage *new_package();
- HistogramMain *plugin;
- int operation;
+ int sum_frames, frames;
};
void process_package(LoadPackage *package);
HistogramEngine *server;
HistogramMain *plugin;
- int *accum[5];
+ int64_t *accum[HISTOGRAM_MODES];
};
class HistogramEngine : public LoadServer
#ifndef HISTOGRAM_INC
#define HISTOGRAM_INC
-
-
-
-
// modes
-#define HISTOGRAM_MODES 4
#define HISTOGRAM_RED 0
#define HISTOGRAM_GREEN 1
#define HISTOGRAM_BLUE 2
#define HISTOGRAM_VALUE 3
+#define HISTOGRAM_MODES 4
// Number of divisions in histogram.
// 65536 + min and max range to speed up the tabulation
class HistogramMain;
-class HistStripePackage;
-class HistStripeUnit;
-class HistStripeEngine;
-
class HistogramPackage;
class HistogramUnit;
class HistogramEngine;
{
plot = 1;
split = 0;
-
+ sum_frames = 0;
reset(1);
}
if(do_mode)
{
automatic = 0;
- automatic_v = 0;
- threshold = 1.0;
+ threshold = 0.97;
}
- frames = 0;
log_slider = .5;
}
}
CLAMP(threshold, 0, 1);
CLAMP(log_slider, 0, 1);
- CLAMP(frames, 0, 65535);
}
int HistogramConfig::equivalent(HistogramConfig &that)
{
// EQUIV isn't precise enough to detect changes in points
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
+ for(int i = 0; i < HISTOGRAM_MODES; i++) {
// if(!EQUIV(low_input[i], that.low_input[i]) ||
// !EQUIV(high_input[i], that.high_input[i]) ||
// !EQUIV(gamma[i], that.gamma[i]) ||
// !EQUIV(low_output[i], that.low_output[i]) ||
// !EQUIV(high_output[i], that.high_output[i])) return 0;
- if(low_input[i] != that.low_input[i] ||
- high_input[i] != that.high_input[i] ||
- gamma[i] != that.gamma[i] ||
- low_output[i] != that.low_output[i] ||
- high_output[i] != that.high_output[i]) return 0;
+ if( low_input[i] != that.low_input[i] ||
+ high_input[i] != that.high_input[i] ||
+ gamma[i] != that.gamma[i] ||
+ low_output[i] != that.low_output[i] ||
+ high_output[i] != that.high_output[i] ) return 0;
}
- if(automatic != that.automatic ||
- automatic_v != that.automatic_v ||
- threshold != that.threshold) return 0;
+ if( automatic != that.automatic ||
+ threshold != that.threshold ) return 0;
- if(plot != that.plot ||
- split != that.split ||
- frames != that.frames ||
- log_slider != that.log_slider ) return 0;
+ if( plot != that.plot ||
+ split != that.split ||
+ sum_frames != that.sum_frames ||
+ log_slider != that.log_slider ) return 0;
return 1;
}
}
automatic = that.automatic;
- automatic_v = that.automatic_v;
threshold = that.threshold;
plot = that.plot;
split = that.split;
- frames = that.frames;
+ sum_frames = that.sum_frames;
log_slider = that.log_slider;
}
-void HistogramConfig::interpolate(HistogramConfig &prev,
- HistogramConfig &next,
- int64_t prev_frame,
- int64_t next_frame,
- int64_t current_frame)
+void HistogramConfig::interpolate(HistogramConfig &prev, HistogramConfig &next,
+ int64_t prev_frame, int64_t next_frame, int64_t current_frame)
{
double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
double prev_scale = 1.0 - next_scale;
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
+ for( int i=0; i<HISTOGRAM_MODES; ++i ) {
low_input[i] = prev.low_input[i] * prev_scale + next.low_input[i] * next_scale;
high_input[i] = prev.high_input[i] * prev_scale + next.high_input[i] * next_scale;
gamma[i] = prev.gamma[i] * prev_scale + next.gamma[i] * next_scale;
threshold = prev.threshold * prev_scale + next.threshold * next_scale;
automatic = prev.automatic;
- automatic_v = prev.automatic_v;
plot = prev.plot;
split = prev.split;
- frames = prev.frames;
+ sum_frames = prev.sum_frames;
log_slider = prev.log_slider;
}
void HistogramConfig::dump()
{
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- printf("HistogramConfig::dump mode=%d plot=%d split=%d frames=%d\n", j, plot, split, frames);
+ for( int j=0; j<HISTOGRAM_MODES; ++j ) {
+ printf("HistogramConfig::dump mode=%d plot=%d split=%d sum_frames=%d\n",
+ j, plot, split, sum_frames);
}
}
-
-
float high_output[HISTOGRAM_MODES];
int automatic;
- int automatic_v;
float threshold;
int plot;
+ int sum_frames;
int split;
- int frames;
float log_slider;
};
threshold->create_objects();
y += automatic->get_h() + margin;
- add_subwindow(plot = new HistogramPlot(plugin, x1, y));
- add_subwindow(select = new HistogramSelect(plugin, this, x2, y));
- frames = new HistogramFrames(plugin, this, x3, y);
- frames->create_objects();
- x = x3 + frames->get_w() + margin;
- add_subwindow(clear_frames = new HistogramClearFrames(plugin, this, x, y));
+ add_subwindow(plot= new HistogramPlot(plugin, x, y));
+ add_subwindow(sum_frames = new HistogramSumFrames(plugin, x2, y));
y += plot->get_h() + margin;
x = x1;
threshold->get_y() + ydiff);
plot->reposition_window(plot->get_x(),
plot->get_y() + ydiff);
+ sum_frames->reposition_window(sum_frames->get_x(),
+ sum_frames->get_y() + ydiff);
split->reposition_window(split->get_x(),
split->get_y() + ydiff);
reset->reposition_window(reset->get_x(),
reset->get_y() + ydiff);
- frames->reposition_window(frames->get_x(),
- frames->get_y() + ydiff);
- select->reposition_window(select->get_x(),
- select->get_y() + ydiff);
- clear_frames->reposition_window(clear_frames->get_x(),
- clear_frames->get_y() + ydiff);
-
update(1, 1, 1, 1);
plugin->w = w;
return result;
}
-void HistogramWindow::update(int do_canvases,
- int do_carrots,
- int do_text,
- int do_toggles)
+void HistogramWindow::update(int do_canvases, int do_carrots, int do_text, int do_toggles)
{
- if(do_toggles)
- {
+ if(do_toggles) {
automatic->update(plugin->config.automatic);
mode_v->update(plugin->mode == HISTOGRAM_VALUE ? 1 : 0);
mode_r->update(plugin->mode == HISTOGRAM_RED ? 1 : 0);
mode_g->update(plugin->mode == HISTOGRAM_GREEN ? 1 : 0);
mode_b->update(plugin->mode == HISTOGRAM_BLUE ? 1 : 0);
plot->update(plugin->config.plot);
+ sum_frames->update(plugin->config.sum_frames);
split->update(plugin->config.split);
- frames->update(plugin->config.frames);
parade_on->update(plugin->parade ? 1 : 0);
parade_off->update(plugin->parade ? 0 : 1);
log_slider->update(plugin->config.log_slider);
output->update();
}
- if(do_canvases)
- {
+ if(do_canvases) {
update_canvas();
}
- if(do_carrots)
- {
+ if(do_carrots) {
low_input_carrot->update();
high_input_carrot->update();
gamma_carrot->update();
high_output_carrot->update();
}
- if(do_text)
- {
+ if(do_text) {
low_input->update();
gamma->update();
high_input->update();
high_output->update();
threshold->update();
}
-
-
}
void HistogramWindow::draw_canvas_mode(int mode, int color, int y, int h)
{
// Draw histogram
- int max = 0, *accum = plugin->accum[mode];
- if( accum ) {
- for( int i=0,x=0; x<canvas_w; ++x ) {
- int m = 0;
- int i1 = (HISTOGRAM_SLOTS * (x+1)) / canvas_w;
- while( i < i1 ) m += accum[i++];
- if( max < m ) max = m;
+ int64_t max = 0;
+ int64_t *accum = plugin->accum[mode];
+ for( int k0=0,x=0; x<canvas_w; ++x ) {
+ int k1 = (HISTOGRAM_SLOTS * (x+1)) / canvas_w;
+ if( k0 == k1 ) continue;
+ int64_t m = accum[k0];
+ for( int k=k0; ++k<k1; ) {
+ if( m < accum[k] ) m = accum[k];
}
+ if( max < m ) max = m;
+ k0 = k1;
}
-
if( max > 0 ) {
double log_slider = plugin->config.log_slider;
double lin_slider = 1. - log_slider;
- double lin_scale = (lin_slider * h) / max;
- double log_scale = (log_slider * h) / log(max);
- for( int i=0,x=0; x<canvas_w; ++x ) {
- int m = 0, i0 = i;
- int i1 = (HISTOGRAM_SLOTS * (x+1)) / canvas_w;
- while( i < i1 ) m += accum[i++];
- double v = m > 0 && i1 > i0 ? (double)m : 0;
- m = v > 0 ? v*lin_scale + log(v)*log_scale : 0;
-
+ double lin_max = (lin_slider * h) / max;
+ double log_max = (log_slider * h) / log(max);
+ for( int k0=0,x=0; x<canvas_w; ++x ) {
+ int k1 = (HISTOGRAM_SLOTS * (x+1)) / canvas_w;
+ if( k0 == k1 ) continue;
+ int64_t m = accum[k0];
+ for( int k=k0; ++k<k1; ) {
+ if( m < accum[k] ) m = accum[k];
+ }
+ int y1 = y+h;
+ double vv = m > 0 ? (double)m : 0;
+ m = vv > 0 ? vv*lin_max + log(vv)*log_max : 0;
canvas->set_color(BLACK);
- canvas->draw_line(x, y, x, y+h - m);
+ int y0 = y1 - m;
+ canvas->draw_line(x, y, x, y0);
canvas->set_color(color);
- canvas->draw_line(x, y+h - m, x, y+h);
+ canvas->draw_line(x, y0, x, y1);
+ k0 = k1;
}
}
else {
// Draw 0 and 100% lines.
canvas->set_color(RED);
int x = (int)(canvas_w * -HIST_MIN_INPUT / FLOAT_RANGE);
- canvas->draw_line(x,
- 0,
- x,
- canvas_h);
+ canvas->draw_line(x, 0, x, canvas_h);
x = (int)(canvas_w * (1.0 - HIST_MIN_INPUT) / FLOAT_RANGE);
- canvas->draw_line(x,
- 0,
- x,
- canvas_h);
+ canvas->draw_line(x, 0, x, canvas_h);
canvas->flash();
}
-
-
-HistogramParade::HistogramParade(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int value)
- : BC_Toggle(x,
- y,
+HistogramParade::HistogramParade(HistogramMain *plugin, HistogramWindow *gui,
+ int x, int y, int value)
+ : BC_Toggle(x, y,
value ? plugin->get_theme()->get_image_set("histogram_rgb_toggle") :
plugin->get_theme()->get_image_set("histogram_toggle"),
0)
{
update(1);
plugin->parade = value;
- gui->update(1,
- 0,
- 0,
- 1);
+ gui->update(1, 0, 0, 1);
return 1;
}
-
-
-
-
-
-
-HistogramCanvas::HistogramCanvas(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int w,
- int h)
- : BC_SubWindow(x,
- y,
- w,
- h,
- BLACK)
+HistogramCanvas::HistogramCanvas(HistogramMain *plugin, HistogramWindow *gui,
+ int x, int y, int w, int h)
+ : BC_SubWindow(x, y, w, h, BLACK)
{
this->plugin = plugin;
this->gui = gui;
}
-HistogramSelect::HistogramSelect(HistogramMain *plugin, HistogramWindow *gui,
- int x, int y)
- : BC_GenericButton(x, y, xS(100), _("Frames"))
-{
- this->plugin = plugin;
- this->gui = gui;
- set_tooltip(_("Set frames to selection duration"));
-}
-int HistogramSelect::handle_event()
-{
- MWindow *mwindow = plugin->server->mwindow;
- if( mwindow ) {
- EDL *edl = mwindow->edl;
- double start = edl->local_session->get_selectionstart();
- int64_t start_pos = edl->get_frame_rate() * start;
- double end = edl->local_session->get_selectionend();
- int64_t end_pos = edl->get_frame_rate() * end;
- int64_t frames = end_pos - start_pos;
- gui->frames->update(frames);
- plugin->config.frames = frames;
- plugin->send_configure_change();
- }
- return 1;
-}
-
-HistogramClearFrames::HistogramClearFrames(HistogramMain *plugin, HistogramWindow *gui,
- int x, int y)
- : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
-{
- this->plugin = plugin;
- this->gui = gui;
- set_tooltip(_("Clear frames"));
-}
-
-int HistogramClearFrames::handle_event()
-{
- plugin->config.frames = 0;
- gui->frames->update(0);
- plugin->send_configure_change();
- return 1;
-}
-
HistogramLogSlider::HistogramLogSlider(HistogramMain *plugin, HistogramWindow *gui,
int x, int y)
: BC_FSlider(x, y, 0, xS(100), xS(100), 0., 1., plugin->config.log_slider)
-
-
-
-
-
-HistogramSlider::HistogramSlider(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int w,
- int h,
- int is_input)
+HistogramSlider::HistogramSlider(HistogramMain *plugin, HistogramWindow *gui,
+ int x, int y, int w, int h, int is_input)
: BC_SubWindow(x, y, w, h)
{
this->plugin = plugin;
clear_box(0, 0, w, h);
- switch(mode)
- {
- case HISTOGRAM_RED:
- g = b = 0x00;
- break;
- case HISTOGRAM_GREEN:
- r = b = 0x00;
- break;
- case HISTOGRAM_BLUE:
- r = g = 0x00;
- break;
+ switch(mode) {
+ case HISTOGRAM_RED:
+ g = b = 0x00;
+ break;
+ case HISTOGRAM_GREEN:
+ r = b = 0x00;
+ break;
+ case HISTOGRAM_BLUE:
+ r = g = 0x00;
+ break;
}
- for(int i = 0; i < w; i++)
- {
+ for( int i = 0; i < w; i++ ) {
int color = (int)(i * 0xff / w);
set_color(((r * color / 0xff) << 16) |
((g * color / 0xff) << 8) |
(b * color / 0xff));
-
draw_line(i, 0, i, h);
}
-
-
flash();
}
-
-
-
-
-
-
-
-HistogramAuto::HistogramAuto(HistogramMain *plugin,
- int x,
- int y)
+HistogramAuto::HistogramAuto(HistogramMain *plugin, int x, int y)
: BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
{
this->plugin = plugin;
}
-
-
-HistogramPlot::HistogramPlot(HistogramMain *plugin,
- int x,
- int y)
+HistogramPlot::HistogramPlot(HistogramMain *plugin, int x, int y)
: BC_CheckBox(x, y, plugin->config.plot, _("Plot histogram"))
{
this->plugin = plugin;
}
+HistogramSumFrames::HistogramSumFrames(HistogramMain *plugin, int x, int y)
+ : BC_CheckBox(x, y, plugin->config.sum_frames, _("Sum frames"))
+{
+ this->plugin = plugin;
+}
+
+int HistogramSumFrames::handle_event()
+{
+ plugin->config.sum_frames = get_value();
+ plugin->send_configure_change();
+ return 1;
+}
-HistogramSplit::HistogramSplit(HistogramMain *plugin,
- int x,
- int y)
+HistogramSplit::HistogramSplit(HistogramMain *plugin, int x, int y)
: BC_CheckBox(x, y, plugin->config.split, _("Split output"))
{
this->plugin = plugin;
HistogramMode::HistogramMode(HistogramMain *plugin,
- int x,
- int y,
- int value,
- char *text)
+ int x, int y, int value, char *text)
: BC_Radial(x, y, plugin->mode == value, text)
{
this->plugin = plugin;
}
-HistogramFrames::HistogramFrames(HistogramMain *plugin, HistogramWindow *gui,
- int x, int y)
- : BC_TumbleTextBox(gui, 0, 0, 65535, x, y, xS(80))
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int HistogramFrames::handle_event()
-{
- plugin->config.frames = atoi(get_text());
- plugin->send_configure_change();
- return 1;
-}
-
-void HistogramFrames::update(int frames)
-{
- BC_TumbleTextBox::update((int64_t)frames);
-}
-
-
HistogramText::HistogramText(HistogramMain *plugin,
HistogramWindow *gui, int x, int y, float hist_min, float hist_max)
: BC_TumbleTextBox(gui, 0.0, hist_min, hist_max, x, y, xS(80))
class HistogramSlider : public BC_SubWindow
{
public:
- HistogramSlider(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int w,
- int h,
- int is_input);
+ HistogramSlider(HistogramMain *plugin, HistogramWindow *gui,
+ int x, int y, int w, int h, int is_input);
void update();
int input_to_pixel(float input);
int operation;
- enum
- {
+ enum {
NONE,
DRAG_INPUT,
DRAG_MIN_OUTPUT,
class HistogramParade : public BC_Toggle
{
public:
- HistogramParade(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int value);
+ HistogramParade(HistogramMain *plugin, HistogramWindow *gui,
+ int x, int y, int value);
int handle_event();
HistogramMain *plugin;
HistogramWindow *gui;
HistogramMain *plugin;
};
+class HistogramSumFrames : public BC_CheckBox
+{
+public:
+ HistogramSumFrames(HistogramMain *plugin, int x, int y);
+ int handle_event();
+ HistogramMain *plugin;
+};
+
class HistogramSplit : public BC_CheckBox
{
public:
HistogramMain *plugin;
};
-class HistogramSelect : public BC_GenericButton
-{
-public:
- HistogramSelect(HistogramMain *plugin, HistogramWindow *gui, int x, int y);
- int handle_event();
- HistogramMain *plugin;
- HistogramWindow *gui;
-};
-
-class HistogramClearFrames : public BC_Button
-{
-public:
- HistogramClearFrames(HistogramMain *plugin, HistogramWindow *gui, int x, int y);
- int handle_event();
- HistogramMain *plugin;
- HistogramWindow *gui;
-};
-
class HistogramLogSlider : public BC_FSlider
{
public:
HistogramWindow *gui;
};
-class HistogramFrames : public BC_TumbleTextBox
-{
-public:
- HistogramFrames(HistogramMain *plugin, HistogramWindow *gui, int x, int y);
- int handle_event();
- void update(int frames);
-
- HistogramMain *plugin;
- HistogramWindow *gui;
-};
-
class HistogramText : public BC_TumbleTextBox
{
public:
HistogramText *low_input;
HistogramText *high_input;
HistogramText *gamma;
- HistogramFrames *frames;
HistogramCanvas *canvas;
HistogramCarrot *low_input_carrot;
HistogramCarrot *gamma_carrot;
BC_Title *canvas_title2;
BC_Title *threshold_title;
BC_Bar *bar;
- HistogramSelect *select;
- HistogramClearFrames *clear_frames;
HistogramLogSlider *log_slider;
BC_Title *log_title1;
BC_Title *log_title2;
int title3_x;
int title4_x;
HistogramPlot *plot;
+ HistogramSumFrames *sum_frames;
HistogramSplit *split;
};
class HistogramCarrot;
class HistogramAuto;
class HistogramPlot;
+class HistogramSumFrames;
class HistogramSplit;
class HistogramMode;
class HistogramReset;
-class HistogramSelect;
class HistogramLogSlider;
-class HistogramFrames;
class HistogramText;
class HistogramCanvas;
class HistogramWindow;
--- /dev/null
+include ../../plugin_defs
+
+OBJS = \
+ $(OBJDIR)/timeblur.o \
+ $(OBJDIR)/timeblurwindow.o
+
+PLUGIN = timeblur
+
+include ../../plugin_config
+
+$(OBJDIR)/timeblur.o: timeblur.C
+$(OBJDIR)/timeblurwindow.o: timeblurwindow.C
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008-2012 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bcprogressbox.h"
+#include "edl.h"
+#include "filexml.h"
+#include "language.h"
+#include "loadbalance.h"
+#include "localsession.h"
+#include "mainsession.h"
+#include "mwindow.h"
+#include "pluginserver.h"
+#include "timeblur.h"
+#include "timeblurwindow.h"
+#include "vframe.h"
+
+REGISTER_PLUGIN(TimeBlurMain)
+
+
+TimeBlurConfig::TimeBlurConfig()
+{
+ frames = 0;
+}
+
+int TimeBlurConfig::equivalent(TimeBlurConfig &that)
+{
+ return frames != that.frames ? 0 : 1;
+}
+
+void TimeBlurConfig::copy_from(TimeBlurConfig &that)
+{
+ frames = that.frames;
+}
+
+void TimeBlurConfig::interpolate(TimeBlurConfig &prev, TimeBlurConfig &next,
+ int64_t prev_frame, int64_t next_frame, int64_t current_frame)
+{
+ frames = prev.frames;
+}
+
+
+TimeBlurMain::TimeBlurMain(PluginServer *server)
+ : PluginVClient(server)
+{
+ stripe_engine = 0;
+ input = 0;
+ fframe = 0;
+ last_frames = 0;
+ last_position = -1;
+}
+
+TimeBlurMain::~TimeBlurMain()
+{
+
+ delete stripe_engine;
+ delete fframe;
+}
+
+const char* TimeBlurMain::plugin_title() { return N_("TimeBlur"); }
+int TimeBlurMain::is_realtime() { return 1; }
+
+
+
+NEW_WINDOW_MACRO(TimeBlurMain, TimeBlurWindow)
+
+LOAD_CONFIGURATION_MACRO(TimeBlurMain, TimeBlurConfig)
+
+
+void TimeBlurMain::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+
+// cause data to be stored directly in text
+ output.set_shared_output(keyframe->xbuf);
+ output.tag.set_title("TIMEBLUR");
+
+ output.tag.set_property("FRAMES", config.frames);
+ output.append_tag();
+ output.tag.set_title("/TIMEBLUR");
+ output.append_tag();
+ output.append_newline();
+ output.terminate_string();
+}
+
+void TimeBlurMain::read_data(KeyFrame *keyframe)
+{
+ FileXML input;
+
+ input.set_shared_input(keyframe->xbuf);
+
+ int result = 0;
+ while( !(result = input.read_tag()) ) {
+ if( input.tag.title_is("TIMEBLUR") ) {
+ config.frames = input.tag.get_property("FRAMES", config.frames);
+ }
+ }
+}
+
+int TimeBlurMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
+{
+ load_configuration();
+ this->input = frame;
+ int cpus = input->get_w() * input->get_h() / 0x80000 + 2;
+ int smps = get_project_smp();
+ if( cpus > smps ) cpus = smps;
+ int frames = config.frames;
+ int use_opengl = 0;
+ MWindow *mwindow = server->mwindow;
+ if( frames > 1 && (!mwindow || // dont scan during SELECT_REGION
+ mwindow->session->current_operation != SELECT_REGION ||
+ mwindow->edl->local_session->get_selectionstart() ==
+ mwindow->edl->local_session->get_selectionend() ) ) {
+ if( !stripe_engine )
+ stripe_engine = new TimeBlurStripeEngine(this, cpus, cpus);
+ int fw = frame->get_w(), fh =frame->get_h();
+ new_temp(fw, fh, BC_RGB_FLOAT);
+ MWindow *mwindow = server->mwindow;
+ if( (mwindow && mwindow->session->current_operation == SELECT_REGION) ||
+ ( last_frames == frames && last_position-1 == start_position &&
+ fframe && fframe->get_w() == fw && fframe->get_h() == fh ) ) {
+ read_frame(temp, 0, start_position, frame_rate, use_opengl);
+ stripe_engine->process_packages(ADD_FFRM);
+ frame->transfer_from(temp);
+ }
+ else if( last_frames != frames || last_position != start_position ||
+ !fframe || fframe->get_w() != fw || fframe->get_h() != fh ) {
+ last_frames = frames;
+ last_position = start_position;
+ VFrame::get_temp(fframe, fw, fh, BC_RGB_FLOAT);
+ read_frame(fframe, 0, start_position+1, frame_rate, use_opengl);
+ BC_ProgressBox *progress = 0;
+ const char *progress_title = _("TimeBlur: scanning\n");
+ Timer timer;
+ for( int i=2; i<frames; ++i ) {
+ read_frame(temp, 0, start_position+i, frame_rate, use_opengl);
+ stripe_engine->process_packages(ADD_TEMP);
+ if( !progress && gui_open() && frames > 2*frame_rate ) {
+ progress = new BC_ProgressBox(-1, -1, progress_title, frames);
+ progress->start();
+ }
+ if( progress && timer.get_difference() > 100 ) {
+ timer.update();
+ progress->update(i, 1);
+ char string[BCTEXTLEN];
+ sprintf(string, "%sframe: %d", progress_title, i);
+ progress->update_title(string, 1);
+ if( progress->is_cancelled() ) break;
+ }
+ if( progress && !gui_open() ) {
+ progress->stop_progress();
+ delete progress; progress = 0;
+ }
+ }
+ read_frame(temp, 0, start_position, frame_rate, use_opengl);
+ stripe_engine->process_packages(ADD_FFRMS);
+ frame->transfer_from(temp);
+ if( progress ) {
+ progress->stop_progress();
+ delete progress;
+ }
+ ++last_position;
+ }
+ else {
+ read_frame(temp, 0, start_position+frames-1, frame_rate, use_opengl);
+ stripe_engine->process_packages(ADD_TEMPS);
+ frame->transfer_from(fframe);
+ read_frame(temp, 0, start_position, frame_rate, use_opengl);
+ stripe_engine->process_packages(SUB_TEMPS);
+ ++last_position;
+ }
+ }
+ else
+ read_frame(frame, 0, start_position, frame_rate, use_opengl);
+ return 0;
+}
+
+
+TimeBlurStripePackage::TimeBlurStripePackage()
+ : LoadPackage()
+{
+}
+
+TimeBlurStripeUnit::TimeBlurStripeUnit(TimeBlurStripeEngine *server, TimeBlurMain *plugin)
+ : LoadClient(server)
+{
+ this->plugin = plugin;
+ this->server = server;
+}
+
+void TimeBlurStripeUnit::process_package(LoadPackage *package)
+{
+ TimeBlurStripePackage *pkg = (TimeBlurStripePackage*)package;
+ int frames = plugin->config.frames;
+ float scale = 1. / frames;
+ int iy0 = pkg->y0, iy1 = pkg->y1;
+ int fw = plugin->fframe->get_w();
+ uint8_t **frows = plugin->fframe->get_rows();
+ uint8_t **trows = plugin->temp->get_rows();
+ switch( server->operation ) {
+ case ADD_TEMP: // add temp to fframe
+ for( int iy=iy0; iy<iy1; ++iy ) {
+ float *trow = (float *)trows[iy];
+ float *frow = (float *)frows[iy];
+ for( int ix=0; ix<fw; ++ix ) {
+ *frow++ += *trow++;
+ *frow++ += *trow++;
+ *frow++ += *trow++;
+ }
+ }
+ break;
+ case ADD_FFRM: // add fframe to scaled temp
+ for( int iy=iy0; iy<iy1; ++iy ) {
+ float *trow = (float *)trows[iy];
+ float *frow = (float *)frows[iy];
+ for( int ix=0; ix<fw; ++ix ) {
+ *trow = *trow * scale + *frow++; ++trow;
+ *trow = *trow * scale + *frow++; ++trow;
+ *trow = *trow * scale + *frow++; ++trow;
+ }
+ }
+ break;
+ case ADD_FFRMS: // add fframe to temp, scale temp, scale fframe
+ for( int iy=iy0; iy<iy1; ++iy ) {
+ float *trow = (float *)trows[iy];
+ float *frow = (float *)frows[iy];
+ for( int ix=0; ix<fw; ++ix ) {
+ *trow += *frow; *trow++ *= scale; *frow++ *= scale;
+ *trow += *frow; *trow++ *= scale; *frow++ *= scale;
+ *trow += *frow; *trow++ *= scale; *frow++ *= scale;
+ }
+ }
+ break;
+ case ADD_TEMPS: // add scaled temp to fframe
+ for( int iy=iy0; iy<iy1; ++iy ) {
+ float *trow = (float *)trows[iy];
+ float *frow = (float *)frows[iy];
+ for( int ix=0; ix<fw; ++ix ) {
+ *frow++ += *trow++ * scale;
+ *frow++ += *trow++ * scale;
+ *frow++ += *trow++ * scale;
+ }
+ }
+ break;
+ case SUB_TEMPS: // sub scaled temp from frame
+ for( int iy=iy0; iy<iy1; ++iy ) {
+ float *trow = (float *)trows[iy];
+ float *frow = (float *)frows[iy];
+ for( int ix=0; ix<fw; ++ix ) {
+ *frow++ -= *trow++ * scale;
+ *frow++ -= *trow++ * scale;
+ *frow++ -= *trow++ * scale;
+ }
+ }
+ break;
+ }
+}
+
+TimeBlurStripeEngine::TimeBlurStripeEngine(TimeBlurMain *plugin,
+ int total_clients, int total_packages)
+ : LoadServer(total_clients, total_packages)
+{
+ this->plugin = plugin;
+}
+void TimeBlurStripeEngine::init_packages()
+{
+ int ih = plugin->input->get_h(), iy0 = 0;
+ for( int i=0,n=get_total_packages(); i<n; ) {
+ TimeBlurStripePackage *pkg = (TimeBlurStripePackage*)get_package(i);
+ int iy1 = (ih * ++i) / n;
+ pkg->y0 = iy0; pkg->y1 = iy1;
+ iy0 = iy1;
+ }
+}
+
+LoadClient* TimeBlurStripeEngine::new_client()
+{
+ return new TimeBlurStripeUnit(this, plugin);
+}
+
+LoadPackage* TimeBlurStripeEngine::new_package()
+{
+ return new TimeBlurStripePackage();
+}
+
+void TimeBlurStripeEngine::process_packages(int operation)
+{
+ this->operation = operation;
+ LoadServer::process_packages();
+}
+
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2011 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 TIMEBLUR_H
+#define TIMEBLUR_H
+
+#include "loadbalance.h"
+#include "pluginvclient.h"
+#include "linklist.h"
+#include <stdint.h>
+
+class TimeBlurConfig;
+class TimeBlurMain;
+class TimeBlurStripePackage;
+class TimeBlurStripeUnit;
+class TimeBlurStripeEngine;
+
+class TimeBlurConfig
+{
+public:
+ TimeBlurConfig();
+ int equivalent(TimeBlurConfig &that);
+ void copy_from(TimeBlurConfig &that);
+ void interpolate(TimeBlurConfig &prev, TimeBlurConfig &next,
+ int64_t prev_frame, int64_t next_frame, int64_t current_frame);
+
+ int frames;
+};
+
+class TimeBlurMain : public PluginVClient
+{
+public:
+ TimeBlurMain(PluginServer *server);
+ ~TimeBlurMain();
+
+ int process_buffer(VFrame *frame,
+ int64_t start_position,
+ double frame_rate);
+ int is_realtime();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
+
+ PLUGIN_CLASS_MEMBERS(TimeBlurConfig)
+
+ VFrame *input;
+ TimeBlurStripeEngine *stripe_engine;
+
+ int w, h;
+ VFrame *fframe;
+ int64_t last_position;
+ int last_frames;
+};
+
+enum { ADD_TEMP, ADD_FFRM, ADD_FFRMS, ADD_TEMPS, SUB_TEMPS };
+
+class TimeBlurStripePackage : public LoadPackage
+{
+public:
+ TimeBlurStripePackage();
+ int y0, y1;
+};
+
+class TimeBlurStripeUnit : public LoadClient
+{
+public:
+ TimeBlurStripeUnit(TimeBlurStripeEngine *server, TimeBlurMain *plugin);
+ void process_package(LoadPackage *package);
+ TimeBlurStripeEngine *server;
+ TimeBlurMain *plugin;
+};
+
+class TimeBlurStripeEngine : public LoadServer
+{
+public:
+ TimeBlurStripeEngine(TimeBlurMain *plugin, int total_clients, int total_packages);
+ void process_packages(int operation);
+ void init_packages();
+ LoadClient *new_client();
+ LoadPackage *new_package();
+ TimeBlurMain *plugin;
+ int operation;
+};
+
+#endif
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "bcdisplayinfo.h"
+#include "bcsignals.h"
+#include "cursors.h"
+#include "edl.h"
+#include "timeblur.h"
+#include "timeblurwindow.h"
+#include "language.h"
+#include "localsession.h"
+#include "mwindow.h"
+#include "pluginserver.h"
+#include "theme.h"
+
+#include <unistd.h>
+
+
+TimeBlurWindow::TimeBlurWindow(TimeBlurMain *plugin)
+ : PluginClientWindow(plugin, xS(250), yS(50), xS(250), yS(50), 0)
+{
+ this->plugin = plugin;
+}
+
+TimeBlurWindow::~TimeBlurWindow()
+{
+}
+
+void TimeBlurWindow::create_objects()
+{
+ int margin = plugin->get_theme()->widget_border;
+ int x = margin, y = margin;
+ int x1 = x;
+ add_subwindow(select = new TimeBlurSelect(plugin, this, x1, y));
+ x1 += select->get_w() + margin;
+ frames = new TimeBlurFrames(plugin, this, x1, y);
+ frames->create_objects();
+ x1 += frames->get_w() + 3*margin;
+ add_subwindow(clear_frames = new TimeBlurClearFrames(plugin, this, x1, y));
+ show_window();
+}
+
+
+TimeBlurSelect::TimeBlurSelect(TimeBlurMain *plugin, TimeBlurWindow *gui,
+ int x, int y)
+ : BC_GenericButton(x, y, xS(100), _("Frames"))
+{
+ this->plugin = plugin;
+ this->gui = gui;
+ set_tooltip(_("Set frames to selection duration"));
+}
+int TimeBlurSelect::handle_event()
+{
+ MWindow *mwindow = plugin->server->mwindow;
+ if( mwindow ) {
+ EDL *edl = mwindow->edl;
+ double start = edl->local_session->get_selectionstart();
+ int64_t start_pos = edl->get_frame_rate() * start;
+ double end = edl->local_session->get_selectionend();
+ int64_t end_pos = edl->get_frame_rate() * end;
+ int64_t frames = end_pos - start_pos;
+ gui->frames->update(frames);
+ plugin->config.frames = frames;
+ plugin->send_configure_change();
+ }
+ return 1;
+}
+
+TimeBlurClearFrames::TimeBlurClearFrames(TimeBlurMain *plugin, TimeBlurWindow *gui,
+ int x, int y)
+ : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
+{
+ this->plugin = plugin;
+ this->gui = gui;
+ set_tooltip(_("Clear frames"));
+}
+
+int TimeBlurClearFrames::handle_event()
+{
+ plugin->config.frames = 0;
+ gui->frames->update(0);
+ plugin->send_configure_change();
+ return 1;
+}
+
+TimeBlurFrames::TimeBlurFrames(TimeBlurMain *plugin, TimeBlurWindow *gui,
+ int x, int y)
+ : BC_TumbleTextBox(gui, 0, 0, 65535, x, y, xS(80))
+{
+ this->plugin = plugin;
+ this->gui = gui;
+}
+
+int TimeBlurFrames::handle_event()
+{
+ plugin->config.frames = atoi(get_text());
+ plugin->send_configure_change();
+ return 1;
+}
+
+void TimeBlurFrames::update(int frames)
+{
+ BC_TumbleTextBox::update((int64_t)frames);
+}
+
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2011 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 TIMEBLURWINDOW_H
+#define TIMEBLURWINDOW_H
+
+#include "timeblur.h"
+
+class TimeBlurSelect;
+class TimeBlurClearFrames;
+class TimeBlurFrames;
+class TimeBlurWindow;
+
+class TimeBlurSelect : public BC_GenericButton
+{
+public:
+ TimeBlurSelect(TimeBlurMain *plugin, TimeBlurWindow *gui, int x, int y);
+ int handle_event();
+ TimeBlurMain *plugin;
+ TimeBlurWindow *gui;
+};
+
+class TimeBlurClearFrames : public BC_Button
+{
+public:
+ TimeBlurClearFrames(TimeBlurMain *plugin, TimeBlurWindow *gui, int x, int y);
+ int handle_event();
+ TimeBlurMain *plugin;
+ TimeBlurWindow *gui;
+};
+
+class TimeBlurFrames : public BC_TumbleTextBox
+{
+public:
+ TimeBlurFrames(TimeBlurMain *plugin, TimeBlurWindow *gui, int x, int y);
+ int handle_event();
+ void update(int frames);
+
+ TimeBlurMain *plugin;
+ TimeBlurWindow *gui;
+};
+
+class TimeBlurWindow : public PluginClientWindow
+{
+public:
+ TimeBlurWindow(TimeBlurMain *plugin);
+ ~TimeBlurWindow();
+
+ void create_objects();
+ TimeBlurMain *plugin;
+ TimeBlurSelect *select;
+ TimeBlurFrames *frames;
+ TimeBlurClearFrames *clear_frames;
+};
+
+#endif