4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "timeavgwindow.h"
31 #include "transportque.h"
43 REGISTER_PLUGIN(TimeAvgMain)
49 TimeAvgConfig::TimeAvgConfig()
52 mode = TimeAvgConfig::AVERAGE;
59 void TimeAvgConfig::copy_from(TimeAvgConfig *src)
61 this->frames = src->frames;
62 this->mode = src->mode;
63 this->paranoid = src->paranoid;
64 this->nosubtract = src->nosubtract;
65 this->threshold = src->threshold;
66 this->border = src->border;
69 int TimeAvgConfig::equivalent(TimeAvgConfig *src)
71 return frames == src->frames &&
73 paranoid == src->paranoid &&
74 nosubtract == src->nosubtract &&
75 threshold == src->threshold &&
76 border == src->border;
91 TimeAvgMain::TimeAvgMain(PluginServer *server)
92 : PluginVClient(server)
98 history_start = -0x7fffffff;
104 TimeAvgMain::~TimeAvgMain()
108 if(accumulation) delete [] accumulation;
111 for(int i = 0; i < config.frames; i++)
115 if(history_frame) delete [] history_frame;
116 if(history_valid) delete [] history_valid;
119 const char* TimeAvgMain::plugin_title() { return _("Time Average"); }
120 int TimeAvgMain::is_realtime() { return 1; }
124 NEW_WINDOW_MACRO(TimeAvgMain, TimeAvgWindow);
128 int TimeAvgMain::process_buffer(VFrame *frame,
129 int64_t start_position,
132 int h = frame->get_h();
133 int w = frame->get_w();
134 int color_model = frame->get_color_model();
136 int reset = load_configuration();
138 // reset buffer on the keyframes
139 int64_t actual_previous_number = start_position;
140 if(get_direction() == PLAY_FORWARD)
142 actual_previous_number--;
143 if(actual_previous_number < get_source_start())
147 KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
148 if(keyframe->position > 0 &&
149 actual_previous_number < keyframe->position)
155 actual_previous_number++;
156 if(actual_previous_number >= get_source_start() + get_total_len())
160 KeyFrame *keyframe = get_next_keyframe(start_position, 1);
161 if(keyframe->position > 0 &&
162 actual_previous_number >= keyframe->position)
167 // Allocate accumulation
168 if(!accumulation || reset)
170 if(!accumulation) accumulation = new unsigned char[w *
172 BC_CModels::components(color_model) *
173 MAX(sizeof(float), sizeof(int))];
174 reset_accum(w, h, color_model);
177 if(!config.nosubtract &&
178 (config.mode == TimeAvgConfig::AVERAGE ||
179 config.mode == TimeAvgConfig::ACCUMULATE ||
180 config.mode == TimeAvgConfig::GREATER ||
181 config.mode == TimeAvgConfig::LESS))
183 // Reallocate history
186 if(config.frames != history_size)
189 int64_t *history_frame2;
191 history2 = new VFrame*[config.frames];
192 history_frame2 = new int64_t[config.frames];
193 history_valid2 = new int[config.frames];
195 // Copy existing frames over
197 for(i = 0, j = 0; i < config.frames && j < history_size; i++, j++)
199 history2[i] = history[j];
200 history_frame2[i] = history_frame[i];
201 history_valid2[i] = history_valid[i];
204 // Delete extra previous frames and subtract from accumulation
205 for( ; j < history_size; j++)
207 subtract_accum(history[j]);
211 delete [] history_frame;
212 delete [] history_valid;
216 for( ; i < config.frames; i++)
218 history2[i] = new VFrame(w, h, color_model);
219 history_frame2[i] = -0x7fffffff;
220 history_valid2[i] = 0;
224 history_frame = history_frame2;
225 history_valid = history_valid2;
227 history_size = config.frames;
233 history = new VFrame*[config.frames];
234 for(int i = 0; i < config.frames; i++)
235 history[i] = new VFrame(w, h, color_model);
236 history_size = config.frames;
237 history_frame = new int64_t[config.frames];
238 bzero(history_frame, sizeof(int64_t) * config.frames);
239 history_valid = new int[config.frames];
240 bzero(history_valid, sizeof(int) * config.frames);
243 //printf("TimeAvgMain::process_buffer %d\n", __LINE__);
248 // Create new history frames based on current frame
249 int64_t *new_history_frames = new int64_t[history_size];
250 for(int i = 0; i < history_size; i++)
252 new_history_frames[history_size - i - 1] = start_position - i;
255 // Subtract old history frames from accumulation buffer
256 // which are not in the new vector
258 for(int i = 0; i < history_size; i++)
260 // Old frame is valid
264 for(int j = 0; j < history_size; j++)
266 // Old frame is equal to a new frame
267 if(history_frame[i] == new_history_frames[j])
274 // Didn't find old frame in new frames
277 if(config.mode == TimeAvgConfig::AVERAGE ||
278 config.mode == TimeAvgConfig::ACCUMULATE)
280 subtract_accum(history[i]);
283 history_valid[i] = 0;
288 // If all frames are still valid, assume tweek occurred upstream and reload.
289 if(config.paranoid && no_change)
291 for(int i = 0; i < history_size; i++)
293 history_valid[i] = 0;
296 if(config.mode == TimeAvgConfig::AVERAGE ||
297 config.mode == TimeAvgConfig::ACCUMULATE)
299 reset_accum(w, h, color_model);
303 // Add new history frames which are not in the old vector
304 for(int i = 0; i < history_size; i++)
306 // Find new frame in old vector
308 for(int j = 0; j < history_size; j++)
310 if(history_valid[j] && history_frame[j] == new_history_frames[i])
317 // Didn't find new frame in old vector
320 // Get first unused entry
321 for(int j = 0; j < history_size; j++)
323 if(!history_valid[j])
325 // Load new frame into it
326 history_frame[j] = new_history_frames[i];
327 history_valid[j] = 1;
328 read_frame(history[j],
333 if(config.mode == TimeAvgConfig::AVERAGE ||
334 config.mode == TimeAvgConfig::ACCUMULATE)
336 add_accum(history[j]);
343 delete [] new_history_frames;
346 // No history subtraction
350 for(int i = 0; i < config.frames; i++)
356 if(history_frame) delete [] history_frame;
357 if(history_valid) delete [] history_valid;
362 // Clamp prev_frame to history size
363 prev_frame = MAX(start_position - config.frames + 1, prev_frame);
365 // Force reload if not repositioned or just started
366 if( (config.paranoid && prev_frame == start_position) ||
369 //printf("TimeAvgMain::process_buffer %d\n", __LINE__);
370 prev_frame = start_position - config.frames + 1;
371 prev_frame = MAX(0, prev_frame);
372 reset_accum(w, h, color_model);
375 // printf("TimeAvgMain::process_buffer %d prev_frame=" _LD " start_position=" _LD "\n",
376 // __LINE__, prev_frame, start_position);
377 for(int64_t i = prev_frame; i <= start_position; i++)
385 printf("TimeAvgMain::process_buffer %d prev_frame=" _LD " start_position=" _LD " i=" _LD "\n",
386 __LINE__, prev_frame, start_position, i);
389 // If we don't add 1, it rereads the frame again
390 prev_frame = start_position + 1;
399 // Transfer accumulation to output with division if average is desired.
400 transfer_accum(frame);
402 //printf("TimeAvgMain::process_buffer %d\n", __LINE__);
417 // Reset accumulation
418 #define SET_ACCUM(type, components, luma, chroma) \
420 type *row = (type*)accumulation; \
423 for(int i = 0; i < w * h; i++) \
428 if(components == 4) *row++ = luma; \
433 bzero(row, w * h * sizeof(type) * components); \
438 void TimeAvgMain::reset_accum(int w, int h, int color_model)
440 if(config.mode == TimeAvgConfig::LESS)
445 SET_ACCUM(int, 3, 0xff, 0xff)
448 SET_ACCUM(float, 3, 1.0, 1.0)
451 SET_ACCUM(int, 4, 0xff, 0xff)
454 SET_ACCUM(float, 4, 1.0, 1.0)
457 SET_ACCUM(int, 3, 0xff, 0x80)
460 SET_ACCUM(int, 4, 0xff, 0x80)
463 SET_ACCUM(int, 3, 0xffff, 0x8000)
465 case BC_YUVA16161616:
466 SET_ACCUM(int, 4, 0xffff, 0x8000)
475 SET_ACCUM(int, 3, 0x0, 0x0)
478 SET_ACCUM(float, 3, 0x0, 0x0)
481 SET_ACCUM(int, 4, 0x0, 0x0)
484 SET_ACCUM(float, 4, 0x0, 0x0)
487 SET_ACCUM(int, 3, 0x0, 0x80)
490 SET_ACCUM(int, 4, 0x0, 0x80)
493 SET_ACCUM(int, 3, 0x0, 0x8000)
495 case BC_YUVA16161616:
496 SET_ACCUM(int, 4, 0x0, 0x8000)
502 #define RGB_TO_VALUE(r, g, b) \
503 ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
505 // Only AVERAGE and ACCUMULATE use this
506 #define SUBTRACT_ACCUM(type, \
511 for(int i = 0; i < h; i++) \
513 accum_type *accum_row = (accum_type*)accumulation + \
514 i * w * components; \
515 type *frame_row = (type*)frame->get_rows()[i]; \
516 for(int j = 0; j < w; j++) \
518 *accum_row++ -= *frame_row++; \
519 *accum_row++ -= (accum_type)*frame_row++ - chroma; \
520 *accum_row++ -= (accum_type)*frame_row++ - chroma; \
521 if(components == 4) *accum_row++ -= *frame_row++; \
527 void TimeAvgMain::subtract_accum(VFrame *frame)
530 if(config.nosubtract) return;
531 int w = frame->get_w();
532 int h = frame->get_h();
534 switch(frame->get_color_model())
537 SUBTRACT_ACCUM(unsigned char, int, 3, 0x0)
540 SUBTRACT_ACCUM(float, float, 3, 0x0)
543 SUBTRACT_ACCUM(unsigned char, int, 4, 0x0)
546 SUBTRACT_ACCUM(float, float, 4, 0x0)
549 SUBTRACT_ACCUM(unsigned char, int, 3, 0x80)
552 SUBTRACT_ACCUM(unsigned char, int, 4, 0x80)
555 SUBTRACT_ACCUM(uint16_t, int, 3, 0x8000)
557 case BC_YUVA16161616:
558 SUBTRACT_ACCUM(uint16_t, int, 4, 0x8000)
564 // The behavior has to be very specific to the color model because we rely on
565 // the value of full black to determine what pixel to show.
566 #define ADD_ACCUM(type, accum_type, components, chroma, max) \
568 if(config.mode == TimeAvgConfig::REPLACE) \
570 type threshold = config.threshold; \
571 if(sizeof(type) == 4) \
573 /* Compare all pixels if border */ \
574 if(config.border > 0) \
576 int border = config.border; \
577 int h_border = h - border - 1; \
578 int w_border = w - border - 1; \
579 int kernel_size = (border * 2 + 1) * (border * 2 + 1); \
580 for(int i = border; i < h_border; i++) \
582 for(int j = border; j < w_border; j++) \
585 for(int k = -border; k <= border; k++) \
587 type *frame_row = (type*)frame->get_rows()[i + k]; \
588 for(int l = -border; l <= border; l++) \
590 type *frame_pixel = frame_row + (j + l) * components; \
591 /* Compare alpha if 4 channel */ \
592 if(components == 4) \
594 if(frame_pixel[3] > threshold) \
598 if(sizeof(type) == 4) \
600 /* Compare luma if 3 channel */ \
601 if(RGB_TO_VALUE(frame_pixel[0], frame_pixel[1], frame_pixel[2]) >= \
610 if(frame_pixel[0] >= threshold) \
616 if(RGB_TO_VALUE(frame_pixel[0], frame_pixel[1], frame_pixel[2]) >= threshold) \
623 if(copy_it == kernel_size) \
625 accum_type *accum_row = (accum_type*)accumulation + \
626 i * w * components + j * components; \
627 type *frame_row = (type*)frame->get_rows()[i] + j * components; \
628 *accum_row++ = *frame_row++; \
629 *accum_row++ = *frame_row++; \
630 *accum_row++ = *frame_row++; \
631 if(components == 4) *accum_row++ = *frame_row++; \
638 /* Compare only relevant pixel if no border */ \
640 for(int i = 0; i < h; i++) \
642 accum_type *accum_row = (accum_type*)accumulation + \
643 i * w * components; \
644 type *frame_row = (type*)frame->get_rows()[i]; \
645 for(int j = 0; j < w; j++) \
648 /* Compare alpha if 4 channel */ \
649 if(components == 4) \
651 if(frame_row[3] > threshold) \
655 if(sizeof(type) == 4) \
657 /* Compare luma if 3 channel */ \
658 if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) >= \
667 if(frame_row[0] >= threshold) \
673 if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) >= threshold) \
680 *accum_row++ = *frame_row++; \
681 *accum_row++ = *frame_row++; \
682 *accum_row++ = *frame_row++; \
683 if(components == 4) *accum_row++ = *frame_row++; \
687 frame_row += components; \
688 accum_row += components; \
695 if(config.mode == TimeAvgConfig::GREATER) \
697 for(int i = 0; i < h; i++) \
699 accum_type *accum_row = (accum_type*)accumulation + \
700 i * w * components; \
701 type *frame_row = (type*)frame->get_rows()[i]; \
702 for(int j = 0; j < w; j++) \
705 /* Compare alpha if 4 channel */ \
706 if(components == 4) \
708 if(frame_row[3] > accum_row[3]) copy_it = 1; \
713 /* Compare YUV luma if 3 channel */ \
714 if(frame_row[0] > accum_row[0]) copy_it = 1; \
718 /* Compare RGB luma if 3 channel */ \
719 if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) > \
720 RGB_TO_VALUE(accum_row[0], accum_row[1], accum_row[2])) \
726 *accum_row++ = *frame_row++; \
727 *accum_row++ = *frame_row++; \
728 *accum_row++ = *frame_row++; \
729 if(components == 4) *accum_row++ = *frame_row++; \
733 accum_row += components; \
734 frame_row += components; \
740 if(config.mode == TimeAvgConfig::LESS) \
742 for(int i = 0; i < h; i++) \
744 accum_type *accum_row = (accum_type*)accumulation + \
745 i * w * components; \
746 type *frame_row = (type*)frame->get_rows()[i]; \
747 for(int j = 0; j < w; j++) \
750 /* Compare alpha if 4 channel */ \
751 if(components == 4) \
753 if(frame_row[3] < accum_row[3]) copy_it = 1; \
758 /* Compare YUV luma if 3 channel */ \
759 if(frame_row[0] < accum_row[0]) copy_it = 1; \
763 /* Compare RGB luma if 3 channel */ \
764 if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) < \
765 RGB_TO_VALUE(accum_row[0], accum_row[1], accum_row[2])) \
771 *accum_row++ = *frame_row++; \
772 *accum_row++ = *frame_row++; \
773 *accum_row++ = *frame_row++; \
774 if(components == 4) *accum_row++ = *frame_row++; \
778 accum_row += components; \
779 frame_row += components; \
786 for(int i = 0; i < h; i++) \
788 accum_type *accum_row = (accum_type*)accumulation + \
789 i * w * components; \
790 type *frame_row = (type*)frame->get_rows()[i]; \
791 for(int j = 0; j < w; j++) \
793 *accum_row++ += *frame_row++; \
794 *accum_row++ += (accum_type)*frame_row++ - chroma; \
795 *accum_row++ += (accum_type)*frame_row++ - chroma; \
796 if(components == 4) *accum_row++ += *frame_row++; \
803 void TimeAvgMain::add_accum(VFrame *frame)
805 int w = frame->get_w();
806 int h = frame->get_h();
808 switch(frame->get_color_model())
811 ADD_ACCUM(unsigned char, int, 3, 0x0, 0xff)
814 ADD_ACCUM(float, float, 3, 0x0, 1.0)
817 ADD_ACCUM(unsigned char, int, 4, 0x0, 0xff)
820 ADD_ACCUM(float, float, 4, 0x0, 1.0)
823 ADD_ACCUM(unsigned char, int, 3, 0x80, 0xff)
826 ADD_ACCUM(unsigned char, int, 4, 0x80, 0xff)
829 ADD_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
831 case BC_YUVA16161616:
832 ADD_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
837 #define TRANSFER_ACCUM(type, accum_type, components, chroma, max) \
839 if(config.mode == TimeAvgConfig::AVERAGE) \
841 accum_type denominator = config.frames; \
842 for(int i = 0; i < h; i++) \
844 accum_type *accum_row = (accum_type*)accumulation + \
845 i * w * components; \
846 type *frame_row = (type*)frame->get_rows()[i]; \
847 for(int j = 0; j < w; j++) \
849 *frame_row++ = *accum_row++ / denominator; \
850 *frame_row++ = (*accum_row++ - chroma) / denominator + chroma; \
851 *frame_row++ = (*accum_row++ - chroma) / denominator + chroma; \
852 if(components == 4) *frame_row++ = *accum_row++ / denominator; \
857 /* Rescan history every time for these modes */ \
858 if(!config.nosubtract && config.mode == TimeAvgConfig::GREATER) \
860 frame->copy_from(history[0]); \
861 for(int k = 1; k < config.frames; k++) \
863 VFrame *history_frame = history[k]; \
865 for(int i = 0; i < h; i++) \
867 type *history_row = (type*)history_frame->get_rows()[i]; \
868 type *frame_row = (type*)frame->get_rows()[i]; \
870 for(int j = 0; j < w; j++) \
873 /* Compare alpha if 4 channel */ \
874 if(components == 4) \
876 if(history_row[3] > frame_row[3]) copy_it = 1; \
881 /* Compare YUV luma if 3 channel */ \
882 if(history_row[0] > frame_row[0]) copy_it = 1; \
886 /* Compare RGB luma if 3 channel */ \
887 if(RGB_TO_VALUE(history_row[0], history_row[1], history_row[2]) > \
888 RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2])) \
894 *frame_row++ = *history_row++; \
895 *frame_row++ = *history_row++; \
896 *frame_row++ = *history_row++; \
897 if(components == 4) *frame_row++ = *history_row++; \
901 frame_row += components; \
902 history_row += components; \
909 if(!config.nosubtract && config.mode == TimeAvgConfig::LESS) \
911 frame->copy_from(history[0]); \
912 for(int k = 1; k < config.frames; k++) \
914 VFrame *history_frame = history[k]; \
916 for(int i = 0; i < h; i++) \
918 type *history_row = (type*)history_frame->get_rows()[i]; \
919 type *frame_row = (type*)frame->get_rows()[i]; \
921 for(int j = 0; j < w; j++) \
924 /* Compare alpha if 4 channel */ \
925 if(components == 4) \
927 if(history_row[3] < frame_row[3]) copy_it = 1; \
932 /* Compare YUV luma if 3 channel */ \
933 if(history_row[0] < frame_row[0]) copy_it = 1; \
937 /* Compare RGB luma if 3 channel */ \
938 if(RGB_TO_VALUE(history_row[0], history_row[1], history_row[2]) < \
939 RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2])) \
945 *frame_row++ = *history_row++; \
946 *frame_row++ = *history_row++; \
947 *frame_row++ = *history_row++; \
948 if(components == 4) *frame_row++ = *history_row++; \
952 frame_row += components; \
953 history_row += components; \
961 for(int i = 0; i < h; i++) \
963 accum_type *accum_row = (accum_type*)accumulation + \
964 i * w * components; \
965 type *frame_row = (type*)frame->get_rows()[i]; \
966 for(int j = 0; j < w; j++) \
968 *frame_row++ = *accum_row++; \
969 *frame_row++ = *accum_row++; \
970 *frame_row++ = *accum_row++; \
971 if(components == 4) *frame_row++ = *accum_row++; \
978 void TimeAvgMain::transfer_accum(VFrame *frame)
980 int w = frame->get_w();
981 int h = frame->get_h();
983 switch(frame->get_color_model())
986 TRANSFER_ACCUM(unsigned char, int, 3, 0x0, 0xff)
989 TRANSFER_ACCUM(float, float, 3, 0x0, 1)
992 TRANSFER_ACCUM(unsigned char, int, 4, 0x0, 0xff)
995 TRANSFER_ACCUM(float, float, 4, 0x0, 1)
998 TRANSFER_ACCUM(unsigned char, int, 3, 0x80, 0xff)
1001 TRANSFER_ACCUM(unsigned char, int, 4, 0x80, 0xff)
1004 TRANSFER_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
1006 case BC_YUVA16161616:
1007 TRANSFER_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
1014 int TimeAvgMain::load_configuration()
1016 KeyFrame *prev_keyframe;
1017 TimeAvgConfig old_config;
1018 old_config.copy_from(&config);
1020 prev_keyframe = get_prev_keyframe(get_source_position());
1021 read_data(prev_keyframe);
1022 return !old_config.equivalent(&config);
1025 void TimeAvgMain::save_data(KeyFrame *keyframe)
1029 // cause data to be stored directly in text
1030 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
1031 output.tag.set_title("TIME_AVERAGE");
1032 output.tag.set_property("FRAMES", config.frames);
1033 output.tag.set_property("MODE", config.mode);
1034 output.tag.set_property("PARANOID", config.paranoid);
1035 output.tag.set_property("NOSUBTRACT", config.nosubtract);
1036 output.tag.set_property("THRESHOLD", config.threshold);
1037 output.tag.set_property("BORDER", config.border);
1038 output.append_tag();
1039 output.terminate_string();
1042 void TimeAvgMain::read_data(KeyFrame *keyframe)
1046 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
1048 while(!input.read_tag())
1050 if(input.tag.title_is("TIME_AVERAGE"))
1052 config.frames = input.tag.get_property("FRAMES", config.frames);
1053 config.mode = input.tag.get_property("MODE", config.mode);
1054 config.paranoid = input.tag.get_property("PARANOID", config.paranoid);
1055 config.nosubtract = input.tag.get_property("NOSUBTRACT", config.nosubtract);
1056 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
1057 config.border = input.tag.get_property("BORDER", config.border);
1063 void TimeAvgMain::update_gui()
1067 if(load_configuration())
1069 thread->window->lock_window("TimeAvgMain::update_gui");
1070 ((TimeAvgWindow*)thread->window)->total_frames->update(config.frames);
1071 ((TimeAvgWindow*)thread->window)->threshold->update(config.threshold);
1072 ((TimeAvgWindow*)thread->window)->update_toggles();
1073 ((TimeAvgWindow*)thread->window)->paranoid->update(config.paranoid);
1074 ((TimeAvgWindow*)thread->window)->no_subtract->update(config.nosubtract);
1075 ((TimeAvgWindow*)thread->window)->threshold->update(config.threshold);
1076 ((TimeAvgWindow*)thread->window)->border->update(config.border);
1077 thread->window->unlock_window();