8 #include "timeavgwindow.h"
20 REGISTER_PLUGIN(TimeAvgMain)
26 TimeAvgConfig::TimeAvgConfig()
29 mode = TimeAvgConfig::AVERAGE;
34 void TimeAvgConfig::copy_from(TimeAvgConfig *src)
36 this->frames = src->frames;
37 this->mode = src->mode;
38 this->paranoid = src->paranoid;
39 this->nosubtract = src->nosubtract;
42 int TimeAvgConfig::equivalent(TimeAvgConfig *src)
44 return frames == src->frames &&
46 paranoid == src->paranoid &&
47 nosubtract == src->nosubtract;
62 TimeAvgMain::TimeAvgMain(PluginServer *server)
63 : PluginVClient(server)
65 PLUGIN_CONSTRUCTOR_MACRO
69 history_start = -0x7fffffff;
75 TimeAvgMain::~TimeAvgMain()
77 PLUGIN_DESTRUCTOR_MACRO
79 if(accumulation) delete [] accumulation;
82 for(int i = 0; i < config.frames; i++)
86 if(history_frame) delete [] history_frame;
87 if(history_valid) delete [] history_valid;
90 char* TimeAvgMain::plugin_title() { return N_("Time Average"); }
91 int TimeAvgMain::is_realtime() { return 1; }
94 NEW_PICON_MACRO(TimeAvgMain)
96 SHOW_GUI_MACRO(TimeAvgMain, TimeAvgThread)
98 SET_STRING_MACRO(TimeAvgMain)
100 RAISE_WINDOW_MACRO(TimeAvgMain);
104 int TimeAvgMain::process_buffer(VFrame *frame,
105 int64_t start_position,
108 int h = frame->get_h();
109 int w = frame->get_w();
110 int color_model = frame->get_color_model();
112 load_configuration();
114 // Allocate accumulation
117 accumulation = new unsigned char[w *
119 cmodel_components(color_model) *
120 MAX(sizeof(float), sizeof(int))];
121 clear_accum(w, h, color_model);
124 if(!config.nosubtract)
126 // Reallocate history
129 if(config.frames != history_size)
132 int64_t *history_frame2;
134 history2 = new VFrame*[config.frames];
135 history_frame2 = new int64_t[config.frames];
136 history_valid2 = new int[config.frames];
138 // Copy existing frames over
140 for(i = 0, j = 0; i < config.frames && j < history_size; i++, j++)
142 history2[i] = history[j];
143 history_frame2[i] = history_frame[i];
144 history_valid2[i] = history_valid[i];
147 // Delete extra previous frames and subtract from accumulation
148 for( ; j < history_size; j++)
150 subtract_accum(history[j]);
154 delete [] history_frame;
155 delete [] history_valid;
159 for( ; i < config.frames; i++)
161 history2[i] = new VFrame(0, w, h, color_model);
162 history_frame2[i] = -0x7fffffff;
163 history_valid2[i] = 0;
167 history_frame = history_frame2;
168 history_valid = history_valid2;
170 history_size = config.frames;
176 history = new VFrame*[config.frames];
177 for(int i = 0; i < config.frames; i++)
178 history[i] = new VFrame(0, w, h, color_model);
179 history_size = config.frames;
180 history_frame = new int64_t[config.frames];
181 bzero(history_frame, sizeof(int64_t) * config.frames);
182 history_valid = new int[config.frames];
183 bzero(history_valid, sizeof(int) * config.frames);
191 // Create new history frames based on current frame
192 int64_t *new_history_frames = new int64_t[history_size];
193 for(int i = 0; i < history_size; i++)
195 new_history_frames[history_size - i - 1] = start_position - i;
198 // Subtract old history frames which are not in the new vector
200 for(int i = 0; i < history_size; i++)
202 // Old frame is valid
206 for(int j = 0; j < history_size; j++)
208 // Old frame is equal to a new frame
209 if(history_frame[i] == new_history_frames[j])
216 // Didn't find old frame in new frames
219 subtract_accum(history[i]);
220 history_valid[i] = 0;
225 // If all frames are still valid, assume tweek occurred upstream and reload.
226 if(config.paranoid && no_change)
228 for(int i = 0; i < history_size; i++)
230 history_valid[i] = 0;
232 clear_accum(w, h, color_model);
235 // Add new history frames which are not in the old vector
236 for(int i = 0; i < history_size; i++)
238 // Find new frame in old vector
240 for(int j = 0; j < history_size; j++)
242 if(history_valid[j] && history_frame[j] == new_history_frames[i])
249 // Didn't find new frame in old vector
252 // Get first unused entry
253 for(int j = 0; j < history_size; j++)
255 if(!history_valid[j])
257 // Load new frame into it
258 history_frame[j] = new_history_frames[i];
259 history_valid[j] = 1;
260 read_frame(history[j],
264 add_accum(history[j]);
270 delete [] new_history_frames;
275 // Force reload if not repositioned or just started
276 if(config.paranoid && prev_frame == start_position ||
279 prev_frame = start_position - config.frames + 1;
280 prev_frame = MAX(0, prev_frame);
281 clear_accum(w, h, color_model);
284 for(int64_t i = prev_frame; i <= start_position; i++)
291 printf("TimeAvgMain::process_buffer 1 %lld %lld %lld\n", prev_frame, start_position, i);
294 prev_frame = start_position;
303 // Transfer accumulation to output with division if average is desired.
304 transfer_accum(frame);
306 printf("TimeAvgMain::process_buffer 2\n");
321 // Reset accumulation
322 #define CLEAR_ACCUM(type, components, chroma) \
324 type *row = (type*)accumulation; \
327 for(int i = 0; i < w * h; i++) \
332 if(components == 4) *row++ = 0x0; \
337 bzero(row, w * h * sizeof(type) * components); \
342 void TimeAvgMain::clear_accum(int w, int h, int color_model)
347 CLEAR_ACCUM(int, 3, 0x0)
350 CLEAR_ACCUM(float, 3, 0x0)
353 CLEAR_ACCUM(int, 4, 0x0)
356 CLEAR_ACCUM(float, 4, 0x0)
359 CLEAR_ACCUM(int, 3, 0x80)
362 CLEAR_ACCUM(int, 4, 0x80)
365 CLEAR_ACCUM(int, 3, 0x8000)
367 case BC_YUVA16161616:
368 CLEAR_ACCUM(int, 4, 0x8000)
374 #define SUBTRACT_ACCUM(type, \
379 if(config.mode == TimeAvgConfig::OR) \
381 for(int i = 0; i < h; i++) \
383 accum_type *accum_row = (accum_type*)accumulation + \
384 i * w * components; \
385 type *frame_row = (type*)frame->get_rows()[i]; \
386 for(int j = 0; j < w; j++) \
388 if(components == 4) \
394 *accum_row++ = chroma; \
395 *accum_row++ = chroma; \
401 if(*frame_row++ != 0 || \
402 *frame_row++ != chroma || \
403 *frame_row++ != chroma) \
406 *accum_row++ = chroma; \
407 *accum_row++ = chroma; \
415 for(int i = 0; i < h; i++) \
417 accum_type *accum_row = (accum_type*)accumulation + \
418 i * w * components; \
419 type *frame_row = (type*)frame->get_rows()[i]; \
420 for(int j = 0; j < w; j++) \
422 *accum_row++ -= *frame_row++; \
423 *accum_row++ -= (accum_type)*frame_row++ - chroma; \
424 *accum_row++ -= (accum_type)*frame_row++ - chroma; \
425 if(components == 4) *accum_row++ -= *frame_row++; \
432 void TimeAvgMain::subtract_accum(VFrame *frame)
435 if(config.nosubtract) return;
436 int w = frame->get_w();
437 int h = frame->get_h();
439 switch(frame->get_color_model())
442 SUBTRACT_ACCUM(unsigned char, int, 3, 0x0)
445 SUBTRACT_ACCUM(float, float, 3, 0x0)
448 SUBTRACT_ACCUM(unsigned char, int, 4, 0x0)
451 SUBTRACT_ACCUM(float, float, 4, 0x0)
454 SUBTRACT_ACCUM(unsigned char, int, 3, 0x80)
457 SUBTRACT_ACCUM(unsigned char, int, 4, 0x80)
460 SUBTRACT_ACCUM(uint16_t, int, 3, 0x8000)
462 case BC_YUVA16161616:
463 SUBTRACT_ACCUM(uint16_t, int, 4, 0x8000)
469 // The behavior has to be very specific to the color model because we rely on
470 // the value of full black to determine what pixel to show.
471 #define ADD_ACCUM(type, accum_type, components, chroma, max) \
473 if(config.mode == TimeAvgConfig::OR) \
475 for(int i = 0; i < h; i++) \
477 accum_type *accum_row = (accum_type*)accumulation + \
478 i * w * components; \
479 type *frame_row = (type*)frame->get_rows()[i]; \
480 for(int j = 0; j < w; j++) \
482 if(components == 4) \
484 accum_type opacity = frame_row[3]; \
485 accum_type transparency = max - opacity; \
486 *accum_row = (opacity * *frame_row + transparency * *accum_row) / max; \
489 *accum_row = chroma + (opacity * (*frame_row - chroma) + transparency * (*accum_row - chroma)) / max; \
492 *accum_row = chroma + (opacity * (*frame_row - chroma) + transparency * (*accum_row - chroma)) / max; \
495 *accum_row = MAX(*frame_row, *accum_row); \
500 if(sizeof(type) == 4) \
502 if(frame_row[0] > 0.001 || \
503 frame_row[1] > 0.001 || \
504 frame_row[2] > 0.001) \
506 *accum_row++ = *frame_row++; \
507 *accum_row++ = *frame_row++; \
508 *accum_row++ = *frame_row++; \
521 *accum_row++ = *frame_row++; \
522 *accum_row++ = *frame_row++; \
523 *accum_row++ = *frame_row++; \
537 *accum_row++ = *frame_row++; \
538 *accum_row++ = *frame_row++; \
539 *accum_row++ = *frame_row++; \
552 for(int i = 0; i < h; i++) \
554 accum_type *accum_row = (accum_type*)accumulation + \
555 i * w * components; \
556 type *frame_row = (type*)frame->get_rows()[i]; \
557 for(int j = 0; j < w; j++) \
559 *accum_row++ += *frame_row++; \
560 *accum_row++ += (accum_type)*frame_row++ - chroma; \
561 *accum_row++ += (accum_type)*frame_row++ - chroma; \
562 if(components == 4) *accum_row++ += *frame_row++; \
569 void TimeAvgMain::add_accum(VFrame *frame)
571 int w = frame->get_w();
572 int h = frame->get_h();
574 switch(frame->get_color_model())
577 ADD_ACCUM(unsigned char, int, 3, 0x0, 0xff)
580 ADD_ACCUM(float, float, 3, 0x0, 1.0)
583 ADD_ACCUM(unsigned char, int, 4, 0x0, 0xff)
586 ADD_ACCUM(float, float, 4, 0x0, 1.0)
589 ADD_ACCUM(unsigned char, int, 3, 0x80, 0xff)
592 ADD_ACCUM(unsigned char, int, 4, 0x80, 0xff)
595 ADD_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
597 case BC_YUVA16161616:
598 ADD_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
603 #define TRANSFER_ACCUM(type, accum_type, components, chroma, max) \
605 if(config.mode == TimeAvgConfig::AVERAGE) \
607 accum_type denominator = config.frames; \
608 for(int i = 0; i < h; i++) \
610 accum_type *accum_row = (accum_type*)accumulation + \
611 i * w * components; \
612 type *frame_row = (type*)frame->get_rows()[i]; \
613 for(int j = 0; j < w; j++) \
615 *frame_row++ = *accum_row++ / denominator; \
616 *frame_row++ = (*accum_row++ - chroma) / denominator + chroma; \
617 *frame_row++ = (*accum_row++ - chroma) / denominator + chroma; \
618 if(components == 4) *frame_row++ = *accum_row++ / denominator; \
623 if(config.mode == TimeAvgConfig::ACCUMULATE) \
625 for(int i = 0; i < h; i++) \
627 accum_type *accum_row = (accum_type*)accumulation + \
628 i * w * components; \
629 type *frame_row = (type*)frame->get_rows()[i]; \
630 for(int j = 0; j < w; j++) \
632 if(sizeof(type) < 4) \
634 accum_type r = *accum_row++; \
635 accum_type g = *accum_row++ + chroma; \
636 accum_type b = *accum_row++ + chroma; \
637 *frame_row++ = CLIP(r, 0, max); \
638 *frame_row++ = CLIP(g, 0, max); \
639 *frame_row++ = CLIP(b, 0, max); \
640 if(components == 4) \
642 accum_type a = *accum_row++; \
643 *frame_row++ = CLIP(a, 0, max); \
648 *frame_row++ = *accum_row++; \
649 *frame_row++ = *accum_row++ + chroma; \
650 *frame_row++ = *accum_row++ + chroma; \
651 if(components == 4) \
653 *frame_row++ = *accum_row++; \
661 for(int i = 0; i < h; i++) \
663 accum_type *accum_row = (accum_type*)accumulation + \
664 i * w * components; \
665 type *frame_row = (type*)frame->get_rows()[i]; \
666 for(int j = 0; j < w; j++) \
668 *frame_row++ = *accum_row++; \
669 *frame_row++ = *accum_row++; \
670 *frame_row++ = *accum_row++; \
671 if(components == 4) *frame_row++ = *accum_row++; \
678 void TimeAvgMain::transfer_accum(VFrame *frame)
680 int w = frame->get_w();
681 int h = frame->get_h();
683 switch(frame->get_color_model())
686 TRANSFER_ACCUM(unsigned char, int, 3, 0x0, 0xff)
689 TRANSFER_ACCUM(float, float, 3, 0x0, 1)
692 TRANSFER_ACCUM(unsigned char, int, 4, 0x0, 0xff)
695 TRANSFER_ACCUM(float, float, 4, 0x0, 1)
698 TRANSFER_ACCUM(unsigned char, int, 3, 0x80, 0xff)
701 TRANSFER_ACCUM(unsigned char, int, 4, 0x80, 0xff)
704 TRANSFER_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
706 case BC_YUVA16161616:
707 TRANSFER_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
713 int TimeAvgMain::load_defaults()
715 char directory[BCTEXTLEN], string[BCTEXTLEN];
716 // set the default directory
717 sprintf(directory, "%stimeavg.rc", BCASTDIR);
720 defaults = new BC_Hash(directory);
723 config.frames = defaults->get("FRAMES", config.frames);
724 config.mode = defaults->get("MODE", config.mode);
725 config.paranoid = defaults->get("PARANOID", config.paranoid);
726 config.nosubtract = defaults->get("NOSUBTRACT", config.nosubtract);
730 int TimeAvgMain::save_defaults()
732 defaults->update("FRAMES", config.frames);
733 defaults->update("MODE", config.mode);
734 defaults->update("PARANOID", config.paranoid);
735 defaults->update("NOSUBTRACT", config.nosubtract);
740 int TimeAvgMain::load_configuration()
742 KeyFrame *prev_keyframe;
743 TimeAvgConfig old_config;
744 old_config.copy_from(&config);
746 prev_keyframe = get_prev_keyframe(get_source_position());
747 read_data(prev_keyframe);
748 return !old_config.equivalent(&config);
751 void TimeAvgMain::save_data(KeyFrame *keyframe)
755 // cause data to be stored directly in text
756 output.set_shared_string(keyframe->data, MESSAGESIZE);
757 output.tag.set_title("TIME_AVERAGE");
758 output.tag.set_property("FRAMES", config.frames);
759 output.tag.set_property("MODE", config.mode);
760 output.tag.set_property("PARANOID", config.paranoid);
761 output.tag.set_property("NOSUBTRACT", config.nosubtract);
763 output.terminate_string();
766 void TimeAvgMain::read_data(KeyFrame *keyframe)
770 input.set_shared_string(keyframe->data, strlen(keyframe->data));
774 while(!input.read_tag())
776 if(input.tag.title_is("TIME_AVERAGE"))
778 config.frames = input.tag.get_property("FRAMES", config.frames);
779 config.mode = input.tag.get_property("MODE", config.mode);
780 config.paranoid = input.tag.get_property("PARANOID", config.paranoid);
781 config.nosubtract = input.tag.get_property("NOSUBTRACT", config.nosubtract);
787 void TimeAvgMain::update_gui()
791 if(load_configuration())
793 thread->window->lock_window("TimeAvgMain::update_gui");
794 thread->window->total_frames->update(config.frames);
795 thread->window->accum->update(config.mode == TimeAvgConfig::ACCUMULATE);
796 thread->window->avg->update(config.mode == TimeAvgConfig::AVERAGE);
797 thread->window->inclusive_or->update(config.mode == TimeAvgConfig::OR);
798 thread->window->paranoid->update(config.paranoid);
799 thread->window->no_subtract->update(config.nosubtract);
800 thread->window->unlock_window();