/* * CINELERRA * Copyright (C) 2008 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "clip.h" #include "bchash.h" #include "filexml.h" #include "keyframe.h" #include "language.h" #include "seltempavg.h" #include "seltempavgwindow.h" #include "vframe.h" #include #include REGISTER_PLUGIN(SelTempAvgMain) ////////////////////////////////////////////////////////////////////// SelTempAvgConfig::SelTempAvgConfig() { frames = 1; method = SelTempAvgConfig::METHOD_SELTEMPAVG; offsetmode = SelTempAvgConfig::OFFSETMODE_RESTARTMARKERSYS; paranoid = 0; nosubtract = 0; offset_restartmarker_keyframe = 0; offset_fixed_value = -15; gain = 1.00; avg_threshold_RY = 0; avg_threshold_GU = 0; avg_threshold_BV = 0; std_threshold_RY = 0; std_threshold_GU = 0; std_threshold_BV = 0; mask_RY = 0; mask_GU = 0; mask_BV = 0; } void SelTempAvgConfig::copy_from(SelTempAvgConfig *src) { this->frames = src->frames; this->method = src->method; this->offsetmode = src->offsetmode; this->paranoid = src->paranoid; this->nosubtract = src->nosubtract; this->offset_restartmarker_keyframe = src->offset_restartmarker_keyframe; this->offset_fixed_value = src->offset_fixed_value; this->gain = src->gain; this->avg_threshold_RY = src->avg_threshold_RY; this->avg_threshold_GU = src->avg_threshold_GU; this->avg_threshold_BV = src->avg_threshold_BV; this->std_threshold_RY = src->std_threshold_RY; this->std_threshold_GU = src->std_threshold_GU; this->std_threshold_BV = src->std_threshold_BV; this->mask_BV = src->mask_BV; this->mask_RY = src->mask_RY; this->mask_GU = src->mask_GU; } int SelTempAvgConfig::equivalent(SelTempAvgConfig *src) { return frames == src->frames && method == src->method && offsetmode == src->offsetmode && paranoid == src->paranoid && offset_restartmarker_keyframe == src->offset_restartmarker_keyframe && offset_fixed_value == src->offset_fixed_value && gain == src->gain && this->avg_threshold_RY == src->avg_threshold_RY && this->avg_threshold_GU == src->avg_threshold_GU && this->avg_threshold_BV == src->avg_threshold_BV && this->std_threshold_RY == src->std_threshold_RY && this->std_threshold_GU == src->std_threshold_GU && this->std_threshold_BV == src->std_threshold_BV && this->mask_RY == src->mask_RY && this->mask_GU == src->mask_GU && this->mask_BV == src->mask_BV; } ////////////////////////////////////////////////////////////////////// SelTempAvgMain::SelTempAvgMain(PluginServer *server) : PluginVClient(server) { accumulation = 0; history = 0; history_size = 0; history_start = -0x7fffffff; history_frame = 0; history_valid = 0; prev_frame = -1; } SelTempAvgMain::~SelTempAvgMain() { if(accumulation) { delete [] accumulation; delete [] accumulation_sq; } if(history) { for(int i = 0; i < config.frames; i++) delete history[i]; delete [] history; } if(history_frame) delete [] history_frame; if(history_valid) delete [] history_valid; } const char* SelTempAvgMain::plugin_title() { return N_("Selective Temporal Averaging"); } int SelTempAvgMain::is_realtime() { return 1; } NEW_WINDOW_MACRO(SelTempAvgMain, SelTempAvgWindow); int SelTempAvgMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate) { int h = frame->get_h(); int w = frame->get_w(); int color_model = frame->get_color_model(); load_configuration(); // Allocate accumulation if(!accumulation) { accumulation = new unsigned char[w * h * BC_CModels::components(color_model) * sizeof(float)]; accumulation_sq = new unsigned char[w * h * 3 * sizeof(float)]; clear_accum(w, h, color_model); } if(!config.nosubtract) { // Reallocate history if(history) { if(config.frames != history_size) { VFrame **history2; int64_t *history_frame2; int *history_valid2; history2 = new VFrame*[config.frames]; history_frame2 = new int64_t[config.frames]; history_valid2 = new int[config.frames]; // Copy existing frames over int i, j; for(i = 0, j = 0; i < config.frames && j < history_size; i++, j++) { history2[i] = history[j]; history_frame2[i] = history_frame[i]; history_valid2[i] = history_valid[i]; } // Delete extra previous frames and subtract from accumulation for( ; j < history_size; j++) { subtract_accum(history[j]); delete history[j]; } delete [] history; delete [] history_frame; delete [] history_valid; // Create new frames for( ; i < config.frames; i++) { history2[i] = new VFrame(w, h, color_model, 0); history_frame2[i] = -0x7fffffff; history_valid2[i] = 0; } history = history2; history_frame = history_frame2; history_valid = history_valid2; history_size = config.frames; } } else // Allocate history { history = new VFrame*[config.frames]; for(int i = 0; i < config.frames; i++) history[i] = new VFrame(w, h, color_model, 0); history_size = config.frames; history_frame = new int64_t[config.frames]; bzero(history_frame, sizeof(int64_t) * config.frames); history_valid = new int[config.frames]; bzero(history_valid, sizeof(int) * config.frames); } // Create new history frames based on current frame int64_t *new_history_frames = new int64_t[history_size]; int64_t theoffset = (int64_t) config.offset_fixed_value; if (config.offsetmode == SelTempAvgConfig::OFFSETMODE_RESTARTMARKERSYS) theoffset = (int64_t) restartoffset; for(int i = 0; i < history_size; i++) { new_history_frames[history_size - i - 1] = start_position + theoffset + i; } // Subtract old history frames which are not in the new vector int no_change = 1; for(int i = 0; i < history_size; i++) { // Old frame is valid if(history_valid[i]) { int got_it = 0; for(int j = 0; j < history_size; j++) { // Old frame is equal to a new frame if(history_frame[i] == new_history_frames[j]) { got_it = 1; break; } } // Didn't find old frame in new frames if(!got_it) { subtract_accum(history[i]); history_valid[i] = 0; no_change = 0; } } } // If all frames are still valid, assume tweek occurred upstream and reload. if(config.paranoid && no_change) { for(int i = 0; i < history_size; i++) { history_valid[i] = 0; } clear_accum(w, h, color_model); } // Add new history frames which are not in the old vector for(int i = 0; i < history_size; i++) { // Find new frame in old vector int got_it = 0; for(int j = 0; j < history_size; j++) { if(history_valid[j] && history_frame[j] == new_history_frames[i]) { got_it = 1; break; } } // Didn't find new frame in old vector if(!got_it) { // Get first unused entry for(int j = 0; j < history_size; j++) { if(!history_valid[j]) { // Load new frame into it history_frame[j] = new_history_frames[i]; history_valid[j] = 1; read_frame(history[j], 0, history_frame[j], frame_rate, 0); add_accum(history[j]); break; } } } } delete [] new_history_frames; } else // No subtraction { // Force reload if not repositioned or just started if( (config.paranoid && prev_frame == start_position) || prev_frame < 0 ) { prev_frame = start_position - config.frames + 1; prev_frame = MAX(0, prev_frame); clear_accum(w, h, color_model); } for(int64_t i = prev_frame; i <= start_position; i++) { read_frame(frame, 0, i, frame_rate, 0); add_accum(frame); //printf("SelTempAvgMain::process_buffer 1 %lld %lld %lld\n", prev_frame, start_position, i); } prev_frame = start_position; } // Read current frame into buffer (needed for the std-deviation tool) read_frame(frame, 0, start_position, frame_rate, 0); // Transfer accumulation to output with division if average is desired. transfer_accum(frame); //printf("SelTempAvgMain::process_buffer 2\n"); return 0; } // Reset accumulation #define CLEAR_ACCUM(type, components, chroma) \ { \ float *row = (float*)accumulation; \ float *row_sq = (float*)accumulation_sq; \ if(chroma) \ { \ for(int i = 0; i < w * h; i++) \ { \ *row++ = 0x0; \ *row++ = 0x0; \ *row++ = 0x0; \ if(components == 4) *row++ = 0x0; \ *row_sq++ = 0x0; \ *row_sq++ = 0x0; \ *row_sq++ = 0x0; \ } \ } \ else \ { \ bzero(row, w * h * sizeof(type) * components); \ bzero(row_sq, w * h * 3 * sizeof(float)); \ } \ } void SelTempAvgMain::clear_accum(int w, int h, int color_model) { switch(color_model) { case BC_RGB888: CLEAR_ACCUM(int, 3, 0x0) break; case BC_RGB_FLOAT: CLEAR_ACCUM(float, 3, 0x0) break; case BC_RGBA8888: CLEAR_ACCUM(int, 4, 0x0) break; case BC_RGBA_FLOAT: CLEAR_ACCUM(float, 4, 0x0) break; case BC_YUV888: CLEAR_ACCUM(int, 3, 0x80) break; case BC_YUVA8888: CLEAR_ACCUM(int, 4, 0x80) break; case BC_YUV161616: CLEAR_ACCUM(int, 3, 0x8000) break; case BC_YUVA16161616: CLEAR_ACCUM(int, 4, 0x8000) break; } } #define C2_IS(frame_row,chroma,max) (float)(frame_row)/max #define SUBTRACT_ACCUM(type, \ components, \ chroma, \ max) \ { \ if(1) \ { \ for(int i = 0; i < h; i++) \ { \ float *accum_row = (float*)accumulation + \ i * w * components; \ float *accum_row_sq = (float*)accumulation_sq + \ i * w *3; \ type *frame_row = (type*)frame->get_rows()[i]; \ float c1, c2, c3; \ for(int j = 0; j < w; j++) \ { \ c1 = ( (float)*frame_row )/max; \ frame_row++; \ c2 = ( (float)*frame_row )/max; \ frame_row++; \ c3 = ( (float)(*frame_row -0) )/max; \ frame_row++; \ \ *accum_row -= c1; \ accum_row++; \ *accum_row -= c2; \ accum_row++; \ *accum_row -= c3; \ accum_row++; \ if(components == 4) { *accum_row -= ((float)*frame_row++)/max; accum_row++; } \ \ *accum_row_sq++ -= c1*c1; \ *accum_row_sq++ -= c2*c2; \ *accum_row_sq++ -= c3*c3; \ } \ } \ } \ } void SelTempAvgMain::subtract_accum(VFrame *frame) { // Just accumulate if(config.nosubtract) return; int w = frame->get_w(); int h = frame->get_h(); switch(frame->get_color_model()) { case BC_RGB888: SUBTRACT_ACCUM(unsigned char, 3, 0x0, 0xff) break; case BC_RGB_FLOAT: SUBTRACT_ACCUM(float, 3, 0x0, 1.0) break; case BC_RGBA8888: SUBTRACT_ACCUM(unsigned char, 4, 0x0, 0xff) break; case BC_RGBA_FLOAT: SUBTRACT_ACCUM(float, 4, 0x0, 1.0) break; case BC_YUV888: SUBTRACT_ACCUM(unsigned char, 3, 0x80, 0xff) break; case BC_YUVA8888: SUBTRACT_ACCUM(unsigned char, 4, 0x80, 0xff) break; case BC_YUV161616: SUBTRACT_ACCUM(uint16_t, 3, 0x8000, 0xffff) break; case BC_YUVA16161616: SUBTRACT_ACCUM(uint16_t, 4, 0x8000, 0xffff) break; } } // The behavior has to be very specific to the color model because we rely on // the value of full black to determine what pixel to show. #define ADD_ACCUM(type, components, chroma, max) \ { \ float c1, c2, c3; \ if(1) \ { \ for(int i = 0; i < h; i++) \ { \ float *accum_row = (float*)accumulation + \ i * w * components; \ float *accum_row_sq = (float*)accumulation_sq + \ i * w *3; \ type *frame_row = (type*)frame->get_rows()[i]; \ for(int j = 0; j < w; j++) \ { \ c1 = ( (float)*frame_row )/max; \ frame_row++; \ c2 = ( (float)*frame_row )/max; \ frame_row++; \ c3 = ( (float)*frame_row )/max; \ frame_row++; \ \ *accum_row += c1; \ accum_row++; \ *accum_row += c2; \ accum_row++; \ *accum_row += c3; \ accum_row++; \ if(components == 4) { *accum_row += ((float)*frame_row++)/max; accum_row++; } \ \ *accum_row_sq++ += c1*c1; \ *accum_row_sq++ += c2*c2; \ *accum_row_sq++ += c3*c3; \ } \ } \ } \ } void SelTempAvgMain::add_accum(VFrame *frame) { int w = frame->get_w(); int h = frame->get_h(); switch(frame->get_color_model()) { case BC_RGB888: ADD_ACCUM(unsigned char, 3, 0x0, 0xff) break; case BC_RGB_FLOAT: ADD_ACCUM(float, 3, 0x0, 1.0) break; case BC_RGBA8888: ADD_ACCUM(unsigned char, 4, 0x0, 0xff) break; case BC_RGBA_FLOAT: ADD_ACCUM(float, 4, 0x0, 1.0) break; case BC_YUV888: ADD_ACCUM(unsigned char, 3, 0x80, 0xff) break; case BC_YUVA8888: ADD_ACCUM(unsigned char, 4, 0x80, 0xff) break; case BC_YUV161616: ADD_ACCUM(uint16_t, 3, 0x8000, 0xffff) break; case BC_YUVA16161616: ADD_ACCUM(uint16_t, 4, 0x8000, 0xffff) break; } } #define MASKER(type, avg_thresh, std_thresh, c_now, c_mean, c_stddev, mask, gain, frame_rowp, max) \ { \ if ( (avg_thresh > fabs(c_now - c_mean)) && (std_thresh > c_stddev) ) \ if (mask) \ frame_rowp = max; \ else \ frame_rowp = (type)(c_mean*max*gain); \ else \ if (mask) \ frame_rowp = 0; \ else \ frame_rowp = (type)(c_now*max*gain); \ } #define TRANSFER_ACCUM(type, components, chroma, max, c1_gain, c2_gain, c3_gain) \ { \ if(config.method == SelTempAvgConfig::METHOD_SELTEMPAVG) \ { \ float denominator = config.frames; \ float c1_now, c2_now, c3_now; \ float c1_mean, c2_mean, c3_mean; \ float c1_stddev, c2_stddev, c3_stddev; \ for(int i = 0; i < h; i++) \ { \ float *accum_row = (float*)accumulation + i * w * components; \ float *accum_row_sq = (float*)accumulation_sq + i * w * 3; \ \ type *frame_row = (type*)frame->get_rows()[i]; \ for(int j = 0; j < w; j++) \ { \ c1_now = (float)(*frame_row)/max; \ frame_row++; \ c2_now = (float)(*frame_row)/max; \ frame_row++; \ c3_now = (float)(*frame_row)/max; \ frame_row -= 2; \ \ c1_mean = *accum_row/denominator; \ accum_row++; \ c2_mean = *accum_row/denominator; \ accum_row++; \ c3_mean = *accum_row/denominator; \ accum_row++; \ if(components == 4) { accum_row++; } \ \ c1_stddev = (*accum_row_sq++)/denominator - c1_mean*c1_mean; \ c2_stddev = (*accum_row_sq++)/denominator - c2_mean*c2_mean; \ c3_stddev = (*accum_row_sq++)/denominator - c3_mean*c3_mean; \ \ MASKER(type, \ config.avg_threshold_RY, \ config.std_threshold_RY, \ c1_now, c1_mean, c1_stddev, config.mask_RY, c1_gain,\ *frame_row++, max)\ MASKER(type, \ config.avg_threshold_GU, \ config.std_threshold_GU, \ c2_now, c2_mean, c2_stddev, config.mask_GU, c2_gain,\ *frame_row++, max)\ MASKER(type, \ config.avg_threshold_BV, \ config.std_threshold_BV, \ c3_now, c3_mean, c3_stddev, config.mask_BV, c3_gain,\ *frame_row++, max)\ if(components == 4) *frame_row++ = max; \ } \ } \ } \ else \ if(config.method == SelTempAvgConfig::METHOD_AVERAGE) \ { \ float denominator = config.frames; \ for(int i = 0; i < h; i++) \ { \ float *accum_row = (float*)accumulation + i * w * components; \ type *frame_row = (type*)frame->get_rows()[i]; \ for(int j = 0; j < w; j++) \ { \ \ *frame_row++ = (type)( (*accum_row++ / denominator)*c1_gain*max ); \ *frame_row++ = (type)( (*accum_row++ / denominator)*c2_gain*max ); \ *frame_row++ = (type)( (*accum_row++ / denominator)*c3_gain*max ); \ if(components == 4) *frame_row++ = (type)((*accum_row++/denominator)*max ); \ } \ } \ } \ else \ if(config.method == SelTempAvgConfig::METHOD_STDDEV) \ { \ float c1_mean, c2_mean, c3_mean; \ float c1_stddev, c2_stddev, c3_stddev; \ float denominator = config.frames; \ for(int i = 0; i < h; i++) \ { \ float *accum_row = (float*)accumulation + i * w * components; \ float *accum_row_sq = (float*)accumulation_sq + i * w * 3; \ type *frame_row = (type*)frame->get_rows()[i]; \ for(int j = 0; j < w; j++) \ { \ \ c1_mean = *accum_row/denominator; \ accum_row++; \ c2_mean = *accum_row/denominator; \ accum_row++; \ c3_mean = *accum_row/denominator; \ accum_row++; \ if(components == 4) { accum_row++; } \ \ c1_stddev = (*accum_row_sq++)/denominator - c1_mean*c1_mean; \ c2_stddev = (*accum_row_sq++)/denominator - c2_mean*c2_mean; \ c3_stddev = (*accum_row_sq++)/denominator - c3_mean*c3_mean; \ \ *frame_row++ = (type)( c1_stddev*c1_gain*max ); \ *frame_row++ = (type)( c2_stddev*c2_gain*max ); \ *frame_row++ = (type)( c3_stddev*c3_gain*max ); \ if(components == 4) *frame_row++ = max; \ } \ } \ } \ } void SelTempAvgMain::transfer_accum(VFrame *frame) { int w = frame->get_w(); int h = frame->get_h(); switch(frame->get_color_model()) { case BC_RGB888: TRANSFER_ACCUM(unsigned char, 3 , 0x0 , 0xff , config.gain, config.gain, config.gain) break; case BC_RGB_FLOAT: TRANSFER_ACCUM(float , 3 , 0x0 , 1 , config.gain, config.gain, config.gain) break; case BC_RGBA8888: TRANSFER_ACCUM(unsigned char, 4 , 0x0 , 0xff , config.gain, config.gain, config.gain) break; case BC_RGBA_FLOAT: TRANSFER_ACCUM(float , 4 , 0x0 , 1 , config.gain, config.gain, config.gain) break; case BC_YUV888: TRANSFER_ACCUM(unsigned char, 3 , 0x80 , 0xff , config.gain, 1.0 , 1.0) break; case BC_YUVA8888: TRANSFER_ACCUM(unsigned char, 4 , 0x80 , 0xff , config.gain, 1.0 , 1.0) break; case BC_YUV161616: TRANSFER_ACCUM(uint16_t , 3 , 0x8000, 0xffff, config.gain, 1.0 , 1.0) break; case BC_YUVA16161616: TRANSFER_ACCUM(uint16_t , 4 , 0x8000, 0xffff, config.gain, 1.0 , 1.0) break; } } int SelTempAvgMain::load_configuration() { KeyFrame *prev_keyframe; KeyFrame *temp_keyframe; SelTempAvgConfig old_config; old_config.copy_from(&config); int64_t curpos = get_source_position(); prev_keyframe = get_prev_keyframe(curpos); read_data(prev_keyframe); if (curpos == prev_keyframe->position) onakeyframe = 1; else onakeyframe = 0; int64_t next_restart_keyframe = curpos + config.frames; int64_t prev_restart_keyframe = curpos - config.frames; for (int i = curpos; i < curpos + config.frames; i++) { temp_keyframe = get_next_keyframe(i); if ( (temp_keyframe->position < curpos + config.frames/2) && (temp_keyframe->position > curpos) && nextkeyframeisoffsetrestart(temp_keyframe) ) { next_restart_keyframe = temp_keyframe->position; i = curpos + config.frames; } else if (temp_keyframe->position > i) i = temp_keyframe->position; } for (int i = curpos; i > curpos - config.frames; i--) { temp_keyframe = get_prev_keyframe(i); if ( (temp_keyframe->position > curpos - config.frames/2) && (temp_keyframe->position < curpos) && nextkeyframeisoffsetrestart(temp_keyframe) ) { prev_restart_keyframe = temp_keyframe->position; i = curpos - config.frames; } else if (temp_keyframe->position < i) i = temp_keyframe->position; } restartoffset = -config.frames/2; if (onakeyframe && config.offset_restartmarker_keyframe) restartoffset = 0; else if ((curpos - prev_restart_keyframe) < config.frames/2) restartoffset = prev_restart_keyframe - curpos; else if ((next_restart_keyframe - curpos) < config.frames/2) { restartoffset = (next_restart_keyframe - curpos) - config.frames; // Probably should put another if in here, (when two "restart" keyframes are close together } return !old_config.equivalent(&config); } void SelTempAvgMain::save_data(KeyFrame *keyframe) { FileXML output; // cause data to be stored directly in text output.set_shared_output(keyframe->xbuf); output.tag.set_title("SELECTIVE_TEMPORAL_AVERAGE"); output.tag.set_property("FRAMES", config.frames); output.tag.set_property("METHOD", config.method); output.tag.set_property("OFFSETMODE", config.offsetmode); output.tag.set_property("PARANOID", config.paranoid); output.tag.set_property("NOSUBTRACT", config.nosubtract); output.tag.set_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe); output.tag.set_property("OFFSETMODE_FIXED_VALUE", config.offset_fixed_value); output.tag.set_property("GAIN", config.gain); output.tag.set_property("AVG_THRESHOLD_RY", config.avg_threshold_RY); output.tag.set_property("AVG_THRESHOLD_GU", config.avg_threshold_GU); output.tag.set_property("AVG_THRESHOLD_BV", config.avg_threshold_BV); output.tag.set_property("STD_THRESHOLD_RY", config.std_threshold_RY); output.tag.set_property("STD_THRESHOLD_GU", config.std_threshold_GU); output.tag.set_property("STD_THRESHOLD_BV", config.std_threshold_BV); output.tag.set_property("MASK_RY", config.mask_RY); output.tag.set_property("MASK_GU", config.mask_GU); output.tag.set_property("MASK_BV", config.mask_BV); output.append_tag(); output.tag.set_title("/SELECTIVE_TEMPORAL_AVERAGE"); output.append_tag(); output.append_newline(); output.terminate_string(); } void SelTempAvgMain::read_data(KeyFrame *keyframe) { FileXML input; input.set_shared_input(keyframe->xbuf); while(!input.read_tag()) { if(input.tag.title_is("SELECTIVE_TEMPORAL_AVERAGE")) { config.frames = input.tag.get_property("FRAMES", config.frames); config.method = input.tag.get_property("METHOD", config.method); config.offsetmode = input.tag.get_property("OFFSETMODE", config.offsetmode); config.paranoid = input.tag.get_property("PARANOID", config.paranoid); config.nosubtract = input.tag.get_property("NOSUBTRACT", config.nosubtract); config.offset_restartmarker_keyframe = input.tag.get_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe); config.offset_fixed_value = input.tag.get_property("OFFSETMODE_FIXED_VALUE", config.offset_fixed_value); config.gain = input.tag.get_property("gain", config.gain); config.avg_threshold_RY = input.tag.get_property("AVG_THRESHOLD_RY", config.avg_threshold_RY); config.avg_threshold_GU = input.tag.get_property("AVG_THRESHOLD_GU", config.avg_threshold_GU); config.avg_threshold_BV = input.tag.get_property("AVG_THRESHOLD_BV", config.avg_threshold_BV); config.std_threshold_RY = input.tag.get_property("STD_THRESHOLD_RY", config.std_threshold_RY); config.std_threshold_GU = input.tag.get_property("STD_THRESHOLD_GU", config.std_threshold_GU); config.std_threshold_BV = input.tag.get_property("STD_THRESHOLD_BV", config.std_threshold_BV); config.mask_RY = input.tag.get_property("MASK_RY", config.mask_RY); config.mask_GU = input.tag.get_property("MASK_GU", config.mask_GU); config.mask_BV = input.tag.get_property("MASK_BV", config.mask_BV); } } } int SelTempAvgMain::nextkeyframeisoffsetrestart(KeyFrame *keyframe) { FileXML input; input.set_shared_input(keyframe->xbuf); while(!input.read_tag()) { if(input.tag.title_is("SELECTIVE_TEMPORAL_AVERAGE")) { return(input.tag.get_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe)); } } return (0); } void SelTempAvgMain::update_gui() { if(thread) { if(load_configuration()) { ((SelTempAvgWindow*)thread->window)->lock_window("SelTempAvgMain::update_gui"); ((SelTempAvgWindow*)thread->window)->total_frames->update(config.frames); ((SelTempAvgWindow*)thread->window)->method_none->update( config.method == SelTempAvgConfig::METHOD_NONE); ((SelTempAvgWindow*)thread->window)->method_seltempavg->update( config.method == SelTempAvgConfig::METHOD_SELTEMPAVG); ((SelTempAvgWindow*)thread->window)->method_average->update( config.method == SelTempAvgConfig::METHOD_AVERAGE); ((SelTempAvgWindow*)thread->window)->method_stddev->update( config.method == SelTempAvgConfig::METHOD_STDDEV); ((SelTempAvgWindow*)thread->window)->offset_fixed->update( config.offsetmode == SelTempAvgConfig::OFFSETMODE_FIXED); ((SelTempAvgWindow*)thread->window)->offset_restartmarker->update(config.offsetmode == SelTempAvgConfig::OFFSETMODE_RESTARTMARKERSYS); ((SelTempAvgWindow*)thread->window)->paranoid->update(config.paranoid); ((SelTempAvgWindow*)thread->window)->no_subtract->update(config.nosubtract); ((SelTempAvgWindow*)thread->window)->offset_fixed_value->update((int64_t)config.offset_fixed_value); ((SelTempAvgWindow*)thread->window)->gain->update(config.gain); ((SelTempAvgWindow*)thread->window)->avg_threshold_RY->update((float)config.avg_threshold_RY); ((SelTempAvgWindow*)thread->window)->avg_threshold_GU->update((float)config.avg_threshold_GU); ((SelTempAvgWindow*)thread->window)->avg_threshold_BV->update((float)config.avg_threshold_BV); ((SelTempAvgWindow*)thread->window)->std_threshold_RY->update((float)config.std_threshold_RY); ((SelTempAvgWindow*)thread->window)->std_threshold_GU->update((float)config.std_threshold_GU); ((SelTempAvgWindow*)thread->window)->std_threshold_BV->update((float)config.std_threshold_BV); ((SelTempAvgWindow*)thread->window)->mask_RY->update(config.mask_RY); ((SelTempAvgWindow*)thread->window)->mask_GU->update(config.mask_GU); ((SelTempAvgWindow*)thread->window)->mask_BV->update(config.mask_BV); ((SelTempAvgWindow*)thread->window)->unlock_window(); } ((SelTempAvgWindow*)thread->window)->offset_restartmarker_pos->update((int64_t)restartoffset); ((SelTempAvgWindow*)thread->window)->offset_restartmarker_keyframe->update((config.offset_restartmarker_keyframe) && (onakeyframe)); } }