prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / plugins / timeavg / timeavg.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "clip.h"
23 #include "bchash.h"
24 #include "filexml.h"
25 #include "format.inc"
26 #include "keyframe.h"
27 #include "language.h"
28 #include "cicolors.h"
29 #include "timeavg.h"
30 #include "timeavgwindow.h"
31 #include "transportque.h"
32 #include "vframe.h"
33
34
35
36
37 #include <stdint.h>
38 #include <string.h>
39
40
41
42
43 REGISTER_PLUGIN(TimeAvgMain)
44
45
46
47
48
49 TimeAvgConfig::TimeAvgConfig()
50 {
51         frames = 1;
52         mode = TimeAvgConfig::AVERAGE;
53         paranoid = 0;
54         nosubtract = 0;
55         threshold = 1;
56         border = 2;
57 }
58
59 void TimeAvgConfig::copy_from(TimeAvgConfig *src)
60 {
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;
67 }
68
69 int TimeAvgConfig::equivalent(TimeAvgConfig *src)
70 {
71         return frames == src->frames &&
72                 mode == src->mode &&
73                 paranoid == src->paranoid &&
74                 nosubtract == src->nosubtract &&
75                 threshold == src->threshold &&
76                 border == src->border;
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91 TimeAvgMain::TimeAvgMain(PluginServer *server)
92  : PluginVClient(server)
93 {
94         
95         accumulation = 0;
96         history = 0;
97         history_size = 0;
98         history_start = -0x7fffffff;
99         history_frame = 0;
100         history_valid = 0;
101         prev_frame = -1;
102 }
103
104 TimeAvgMain::~TimeAvgMain()
105 {
106         
107
108         if(accumulation) delete [] accumulation;
109         if(history)
110         {
111                 for(int i = 0; i < config.frames; i++)
112                         delete history[i];
113                 delete [] history;
114         }
115         if(history_frame) delete [] history_frame;
116         if(history_valid) delete [] history_valid;
117 }
118
119 const char* TimeAvgMain::plugin_title() { return _("Time Average"); }
120 int TimeAvgMain::is_realtime() { return 1; }
121
122
123
124 NEW_WINDOW_MACRO(TimeAvgMain, TimeAvgWindow);
125
126
127
128 int TimeAvgMain::process_buffer(VFrame *frame,
129                 int64_t start_position,
130                 double frame_rate)
131 {
132         int h = frame->get_h();
133         int w = frame->get_w();
134         int color_model = frame->get_color_model();
135
136         int reset = load_configuration();
137
138 // reset buffer on the keyframes
139         int64_t actual_previous_number = start_position;
140         if(get_direction() == PLAY_FORWARD)
141         {
142                 actual_previous_number--;
143                 if(actual_previous_number < get_source_start())
144                         reset = 1;
145                 else
146                 {
147                         KeyFrame *keyframe = get_prev_keyframe(start_position, 1);
148                         if(keyframe->position > 0 &&
149                                 actual_previous_number < keyframe->position)
150                                 reset = 1;
151                 }
152         }
153         else
154         {
155                 actual_previous_number++;
156                 if(actual_previous_number >= get_source_start() + get_total_len())
157                         reset = 1;
158                 else
159                 {
160                         KeyFrame *keyframe = get_next_keyframe(start_position, 1);
161                         if(keyframe->position > 0 &&
162                                 actual_previous_number >= keyframe->position)
163                                 reset = 1;
164                 }
165         }
166
167 // Allocate accumulation
168         if(!accumulation || reset)
169         {
170                 if(!accumulation) accumulation = new unsigned char[w * 
171                         h * 
172                         BC_CModels::components(color_model) *
173                         MAX(sizeof(float), sizeof(int))];
174                 reset_accum(w, h, color_model);
175         }
176
177         if(!config.nosubtract &&
178                 (config.mode == TimeAvgConfig::AVERAGE ||
179                 config.mode == TimeAvgConfig::ACCUMULATE ||
180                 config.mode == TimeAvgConfig::GREATER ||
181                 config.mode == TimeAvgConfig::LESS))
182         {
183 // Reallocate history
184                 if(history)
185                 {
186                         if(config.frames != history_size)
187                         {
188                                 VFrame **history2;
189                                 int64_t *history_frame2;
190                                 int *history_valid2;
191                                 history2 = new VFrame*[config.frames];
192                                 history_frame2 = new int64_t[config.frames];
193                                 history_valid2 = new int[config.frames];
194
195 // Copy existing frames over
196                                 int i, j;
197                                 for(i = 0, j = 0; i < config.frames && j < history_size; i++, j++)
198                                 {
199                                         history2[i] = history[j];
200                                         history_frame2[i] = history_frame[i];
201                                         history_valid2[i] = history_valid[i];
202                                 }
203
204 // Delete extra previous frames and subtract from accumulation
205                                 for( ; j < history_size; j++)
206                                 {
207                                         subtract_accum(history[j]);
208                                         delete history[j];
209                                 }
210                                 delete [] history;
211                                 delete [] history_frame;
212                                 delete [] history_valid;
213
214
215 // Create new frames
216                                 for( ; i < config.frames; i++)
217                                 {
218                                         history2[i] = new VFrame(w, h, color_model);
219                                         history_frame2[i] = -0x7fffffff;
220                                         history_valid2[i] = 0;
221                                 }
222
223                                 history = history2;
224                                 history_frame = history_frame2;
225                                 history_valid = history_valid2;
226
227                                 history_size = config.frames;
228                         }
229                 }
230                 else
231 // Allocate history
232                 {
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);
241                 }
242
243 //printf("TimeAvgMain::process_buffer %d\n", __LINE__);
244
245
246
247
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++)
251                 {
252                         new_history_frames[history_size - i - 1] = start_position - i;
253                 }
254
255 // Subtract old history frames from accumulation buffer
256 // which are not in the new vector
257                 int no_change = 1;
258                 for(int i = 0; i < history_size; i++)
259                 {
260 // Old frame is valid
261                         if(history_valid[i])
262                         {
263                                 int got_it = 0;
264                                 for(int j = 0; j < history_size; j++)
265                                 {
266 // Old frame is equal to a new frame
267                                         if(history_frame[i] == new_history_frames[j]) 
268                                         {
269                                                 got_it = 1;
270                                                 break;
271                                         }
272                                 }
273
274 // Didn't find old frame in new frames
275                                 if(!got_it)
276                                 {
277                                         if(config.mode == TimeAvgConfig::AVERAGE ||
278                                                 config.mode == TimeAvgConfig::ACCUMULATE)
279                                         {
280                                                 subtract_accum(history[i]);
281                                         }
282
283                                         history_valid[i] = 0;
284                                         no_change = 0;
285                                 }
286                         }
287                 }
288 // If all frames are still valid, assume tweek occurred upstream and reload.
289                 if(config.paranoid && no_change)
290                 {
291                         for(int i = 0; i < history_size; i++)
292                         {
293                                 history_valid[i] = 0;
294                         }
295
296                         if(config.mode == TimeAvgConfig::AVERAGE ||
297                                 config.mode == TimeAvgConfig::ACCUMULATE)
298                         {
299                                 reset_accum(w, h, color_model);
300                         }
301                 }
302
303 // Add new history frames which are not in the old vector
304                 for(int i = 0; i < history_size; i++)
305                 {
306 // Find new frame in old vector
307                         int got_it = 0;
308                         for(int j = 0; j < history_size; j++)
309                         {
310                                 if(history_valid[j] && history_frame[j] == new_history_frames[i])
311                                 {
312                                         got_it = 1;
313                                         break;
314                                 }
315                         }
316
317 // Didn't find new frame in old vector
318                         if(!got_it)
319                         {
320 // Get first unused entry
321                                 for(int j = 0; j < history_size; j++)
322                                 {
323                                         if(!history_valid[j])
324                                         {
325 // Load new frame into it
326                                                 history_frame[j] = new_history_frames[i];
327                                                 history_valid[j] = 1;
328                                                 read_frame(history[j],
329                                                         0,
330                                                         history_frame[j],
331                                                         frame_rate,
332                                                         0);
333                                                 if(config.mode == TimeAvgConfig::AVERAGE ||
334                                                         config.mode == TimeAvgConfig::ACCUMULATE)
335                                                 {
336                                                         add_accum(history[j]);
337                                                 }
338                                                 break;
339                                         }
340                                 }
341                         }
342                 }
343                 delete [] new_history_frames;
344         }
345         else
346 // No history subtraction
347         {
348                 if(history)
349                 {
350                         for(int i = 0; i < config.frames; i++)
351                                 delete history[i];
352                         delete [] history;
353                         history = 0;
354                 }
355
356                 if(history_frame) delete [] history_frame;
357                 if(history_valid) delete [] history_valid;
358                 history_frame = 0;
359                 history_valid = 0;
360                 history_size = 0;
361
362 // Clamp prev_frame to history size
363                 prev_frame = MAX(start_position - config.frames + 1, prev_frame);
364
365 // Force reload if not repositioned or just started
366                 if( (config.paranoid && prev_frame == start_position) ||
367                         prev_frame < 0)
368                 {
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);
373                 }
374
375 // printf("TimeAvgMain::process_buffer %d prev_frame=%jd start_position=%jd\n", 
376 //   __LINE__, prev_frame, start_position);
377                 for(int64_t i = prev_frame; i <= start_position; i++)
378                 {
379                         read_frame(frame,
380                                 0,
381                                 i,
382                                 frame_rate,
383                                 0);
384                         add_accum(frame);
385 printf("TimeAvgMain::process_buffer %d prev_frame=%jd start_position=%jd i=%jd\n", 
386   __LINE__, prev_frame, start_position, i);
387                 }
388
389 // If we don't add 1, it rereads the frame again
390                 prev_frame = start_position + 1;
391         }
392
393
394
395
396
397
398
399 // Transfer accumulation to output with division if average is desired.
400         transfer_accum(frame);
401
402 //printf("TimeAvgMain::process_buffer %d\n", __LINE__);
403
404
405         return 0;
406 }
407
408
409
410
411
412
413
414
415
416
417 // Reset accumulation
418 #define SET_ACCUM(type, components, luma, chroma) \
419 { \
420         type *row = (type*)accumulation; \
421         if(chroma) \
422         { \
423                 for(int i = 0; i < w * h; i++) \
424                 { \
425                         *row++ = luma; \
426                         *row++ = chroma; \
427                         *row++ = chroma; \
428                         if(components == 4) *row++ = luma; \
429                 } \
430         } \
431         else \
432         { \
433                 bzero(row, w * h * sizeof(type) * components); \
434         } \
435 }
436
437
438 void TimeAvgMain::reset_accum(int w, int h, int color_model)
439 {
440         if(config.mode == TimeAvgConfig::LESS)
441         {
442                 switch(color_model)
443                 {
444                         case BC_RGB888:
445                                 SET_ACCUM(int, 3, 0xff, 0xff)
446                                 break;
447                         case BC_RGB_FLOAT:
448                                 SET_ACCUM(float, 3, 1.0, 1.0)
449                                 break;
450                         case BC_RGBA8888:
451                                 SET_ACCUM(int, 4, 0xff, 0xff)
452                                 break;
453                         case BC_RGBA_FLOAT:
454                                 SET_ACCUM(float, 4, 1.0, 1.0)
455                                 break;
456                         case BC_YUV888:
457                                 SET_ACCUM(int, 3, 0xff, 0x80)
458                                 break;
459                         case BC_YUVA8888:
460                                 SET_ACCUM(int, 4, 0xff, 0x80)
461                                 break;
462                         case BC_YUV161616:
463                                 SET_ACCUM(int, 3, 0xffff, 0x8000)
464                                 break;
465                         case BC_YUVA16161616:
466                                 SET_ACCUM(int, 4, 0xffff, 0x8000)
467                                 break;
468                 }
469         }
470         else
471         {
472                 switch(color_model)
473                 {
474                         case BC_RGB888:
475                                 SET_ACCUM(int, 3, 0x0, 0x0)
476                                 break;
477                         case BC_RGB_FLOAT:
478                                 SET_ACCUM(float, 3, 0x0, 0x0)
479                                 break;
480                         case BC_RGBA8888:
481                                 SET_ACCUM(int, 4, 0x0, 0x0)
482                                 break;
483                         case BC_RGBA_FLOAT:
484                                 SET_ACCUM(float, 4, 0x0, 0x0)
485                                 break;
486                         case BC_YUV888:
487                                 SET_ACCUM(int, 3, 0x0, 0x80)
488                                 break;
489                         case BC_YUVA8888:
490                                 SET_ACCUM(int, 4, 0x0, 0x80)
491                                 break;
492                         case BC_YUV161616:
493                                 SET_ACCUM(int, 3, 0x0, 0x8000)
494                                 break;
495                         case BC_YUVA16161616:
496                                 SET_ACCUM(int, 4, 0x0, 0x8000)
497                                 break;
498                 }
499         }
500 }
501
502 #define RGB_TO_VALUE(r, g, b) \
503 ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
504
505 // Only AVERAGE and ACCUMULATE use this
506 #define SUBTRACT_ACCUM(type, \
507         accum_type, \
508         components, \
509         chroma) \
510 { \
511         for(int i = 0; i < h; i++) \
512         { \
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++) \
517                 { \
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++; \
522                 } \
523         } \
524 }
525
526
527 void TimeAvgMain::subtract_accum(VFrame *frame)
528 {
529 // Just accumulate
530         if(config.nosubtract) return;
531         int w = frame->get_w();
532         int h = frame->get_h();
533
534         switch(frame->get_color_model())
535         {
536                 case BC_RGB888:
537                         SUBTRACT_ACCUM(unsigned char, int, 3, 0x0)
538                         break;
539                 case BC_RGB_FLOAT:
540                         SUBTRACT_ACCUM(float, float, 3, 0x0)
541                         break;
542                 case BC_RGBA8888:
543                         SUBTRACT_ACCUM(unsigned char, int, 4, 0x0)
544                         break;
545                 case BC_RGBA_FLOAT:
546                         SUBTRACT_ACCUM(float, float, 4, 0x0)
547                         break;
548                 case BC_YUV888:
549                         SUBTRACT_ACCUM(unsigned char, int, 3, 0x80)
550                         break;
551                 case BC_YUVA8888:
552                         SUBTRACT_ACCUM(unsigned char, int, 4, 0x80)
553                         break;
554                 case BC_YUV161616:
555                         SUBTRACT_ACCUM(uint16_t, int, 3, 0x8000)
556                         break;
557                 case BC_YUVA16161616:
558                         SUBTRACT_ACCUM(uint16_t, int, 4, 0x8000)
559                         break;
560         }
561 }
562
563
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) \
567 { \
568         if(config.mode == TimeAvgConfig::REPLACE) \
569         { \
570                 type threshold = config.threshold; \
571                 if(sizeof(type) == 4) \
572                         threshold /= 256; \
573 /* Compare all pixels if border */ \
574                 if(config.border > 0) \
575                 { \
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++) \
581                         { \
582                                 for(int j = border; j < w_border; j++) \
583                                 { \
584                                         int copy_it = 0; \
585                                         for(int k = -border; k <= border; k++) \
586                                         { \
587                                                 type *frame_row = (type*)frame->get_rows()[i + k]; \
588                                                 for(int l = -border; l <= border; l++) \
589                                                 { \
590                                                         type *frame_pixel = frame_row + (j + l) * components; \
591 /* Compare alpha if 4 channel */ \
592                                                         if(components == 4) \
593                                                         { \
594                                                                 if(frame_pixel[3] > threshold) \
595                                                                         copy_it++; \
596                                                         } \
597                                                         else \
598                                                         if(sizeof(type) == 4) \
599                                                         { \
600 /* Compare luma if 3 channel */ \
601                                                                 if(RGB_TO_VALUE(frame_pixel[0], frame_pixel[1], frame_pixel[2]) >= \
602                                                                         threshold) \
603                                                                 { \
604                                                                         copy_it++; \
605                                                                 } \
606                                                         } \
607                                                         else \
608                                                         if(chroma) \
609                                                         { \
610                                                                 if(frame_pixel[0] >= threshold) \
611                                                                 { \
612                                                                         copy_it++; \
613                                                                 } \
614                                                         } \
615                                                         else \
616                                                         if(RGB_TO_VALUE(frame_pixel[0], frame_pixel[1], frame_pixel[2]) >= threshold) \
617                                                         { \
618                                                                 copy_it++; \
619                                                         } \
620                                                 } \
621                                         } \
622  \
623                                         if(copy_it == kernel_size) \
624                                         { \
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++; \
632                                         } \
633  \
634                                 } \
635                         } \
636                 } \
637                 else \
638 /* Compare only relevant pixel if no border */ \
639                 { \
640                         for(int i = 0; i < h; i++) \
641                         { \
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++) \
646                                 { \
647                                         int copy_it = 0; \
648 /* Compare alpha if 4 channel */ \
649                                         if(components == 4) \
650                                         { \
651                                                 if(frame_row[3] > threshold) \
652                                                         copy_it = 1; \
653                                         } \
654                                         else \
655                                         if(sizeof(type) == 4) \
656                                         { \
657 /* Compare luma if 3 channel */ \
658                                                 if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) >= \
659                                                         threshold) \
660                                                 { \
661                                                         copy_it = 1; \
662                                                 } \
663                                         } \
664                                         else \
665                                         if(chroma) \
666                                         { \
667                                                 if(frame_row[0] >= threshold) \
668                                                 { \
669                                                         copy_it = 1; \
670                                                 } \
671                                         } \
672                                         else \
673                                         if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) >= threshold) \
674                                         { \
675                                                 copy_it = 1; \
676                                         } \
677  \
678                                         if(copy_it) \
679                                         { \
680                                                 *accum_row++ = *frame_row++; \
681                                                 *accum_row++ = *frame_row++; \
682                                                 *accum_row++ = *frame_row++; \
683                                                 if(components == 4) *accum_row++ = *frame_row++; \
684                                         } \
685                                         else \
686                                         { \
687                                                 frame_row += components; \
688                                                 accum_row += components; \
689                                         } \
690                                 } \
691                         } \
692                 } \
693         } \
694         else \
695         if(config.mode == TimeAvgConfig::GREATER) \
696         { \
697                 for(int i = 0; i < h; i++) \
698                 { \
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++) \
703                         { \
704                                 int copy_it = 0; \
705 /* Compare alpha if 4 channel */ \
706                                 if(components == 4) \
707                                 { \
708                                         if(frame_row[3] > accum_row[3]) copy_it = 1; \
709                                 } \
710                                 else \
711                                 if(chroma) \
712                                 { \
713 /* Compare YUV luma if 3 channel */ \
714                                         if(frame_row[0] > accum_row[0]) copy_it = 1; \
715                                 } \
716                                 else \
717                                 { \
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])) \
721                                                 copy_it = 1; \
722                                 } \
723  \
724                                 if(copy_it) \
725                                 { \
726                                         *accum_row++ = *frame_row++; \
727                                         *accum_row++ = *frame_row++; \
728                                         *accum_row++ = *frame_row++; \
729                                         if(components == 4) *accum_row++ = *frame_row++; \
730                                 } \
731                                 else \
732                                 { \
733                                         accum_row += components; \
734                                         frame_row += components; \
735                                 } \
736                         } \
737                 } \
738         } \
739         else \
740         if(config.mode == TimeAvgConfig::LESS) \
741         { \
742                 for(int i = 0; i < h; i++) \
743                 { \
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++) \
748                         { \
749                                 int copy_it = 0; \
750 /* Compare alpha if 4 channel */ \
751                                 if(components == 4) \
752                                 { \
753                                         if(frame_row[3] < accum_row[3]) copy_it = 1; \
754                                 } \
755                                 else \
756                                 if(chroma) \
757                                 { \
758 /* Compare YUV luma if 3 channel */ \
759                                         if(frame_row[0] < accum_row[0]) copy_it = 1; \
760                                 } \
761                                 else \
762                                 { \
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])) \
766                                                 copy_it = 1; \
767                                 } \
768  \
769                                 if(copy_it) \
770                                 { \
771                                         *accum_row++ = *frame_row++; \
772                                         *accum_row++ = *frame_row++; \
773                                         *accum_row++ = *frame_row++; \
774                                         if(components == 4) *accum_row++ = *frame_row++; \
775                                 } \
776                                 else \
777                                 { \
778                                         accum_row += components; \
779                                         frame_row += components; \
780                                 } \
781                         } \
782                 } \
783         } \
784         else \
785         { \
786                 for(int i = 0; i < h; i++) \
787                 { \
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++) \
792                         { \
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++; \
797                         } \
798                 } \
799         } \
800 }
801
802
803 void TimeAvgMain::add_accum(VFrame *frame)
804 {
805         int w = frame->get_w();
806         int h = frame->get_h();
807
808         switch(frame->get_color_model())
809         {
810                 case BC_RGB888:
811                         ADD_ACCUM(unsigned char, int, 3, 0x0, 0xff)
812                         break;
813                 case BC_RGB_FLOAT:
814                         ADD_ACCUM(float, float, 3, 0x0, 1.0)
815                         break;
816                 case BC_RGBA8888:
817                         ADD_ACCUM(unsigned char, int, 4, 0x0, 0xff)
818                         break;
819                 case BC_RGBA_FLOAT:
820                         ADD_ACCUM(float, float, 4, 0x0, 1.0)
821                         break;
822                 case BC_YUV888:
823                         ADD_ACCUM(unsigned char, int, 3, 0x80, 0xff)
824                         break;
825                 case BC_YUVA8888:
826                         ADD_ACCUM(unsigned char, int, 4, 0x80, 0xff)
827                         break;
828                 case BC_YUV161616:
829                         ADD_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
830                         break;
831                 case BC_YUVA16161616:
832                         ADD_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
833                         break;
834         }
835 }
836
837 #define TRANSFER_ACCUM(type, accum_type, components, chroma, max) \
838 { \
839         if(config.mode == TimeAvgConfig::AVERAGE) \
840         { \
841                 accum_type denominator = config.frames; \
842                 for(int i = 0; i < h; i++) \
843                 { \
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++) \
848                         { \
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; \
853                         } \
854                 } \
855         } \
856         else \
857 /* Rescan history every time for these modes */ \
858         if(!config.nosubtract && config.mode == TimeAvgConfig::GREATER) \
859         { \
860                 frame->copy_from(history[0]); \
861                 for(int k = 1; k < config.frames; k++) \
862                 { \
863                         VFrame *history_frame = history[k]; \
864  \
865                         for(int i = 0; i < h; i++) \
866                         { \
867                                 type *history_row = (type*)history_frame->get_rows()[i]; \
868                                 type *frame_row = (type*)frame->get_rows()[i]; \
869  \
870                                 for(int j = 0; j < w; j++) \
871                                 { \
872                                         int copy_it = 0; \
873 /* Compare alpha if 4 channel */ \
874                                         if(components == 4) \
875                                         { \
876                                                 if(history_row[3] > frame_row[3]) copy_it = 1; \
877                                         } \
878                                         else \
879                                         if(chroma) \
880                                         { \
881 /* Compare YUV luma if 3 channel */ \
882                                                 if(history_row[0] > frame_row[0]) copy_it = 1; \
883                                         } \
884                                         else \
885                                         { \
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])) \
889                                                         copy_it = 1; \
890                                         } \
891  \
892                                         if(copy_it) \
893                                         { \
894                                                 *frame_row++ = *history_row++; \
895                                                 *frame_row++ = *history_row++; \
896                                                 *frame_row++ = *history_row++; \
897                                                 if(components == 4) *frame_row++ = *history_row++; \
898                                         } \
899                                         else \
900                                         { \
901                                                 frame_row += components; \
902                                                 history_row += components; \
903                                         } \
904                                 } \
905                         } \
906                 } \
907         } \
908         else \
909         if(!config.nosubtract && config.mode == TimeAvgConfig::LESS) \
910         { \
911                 frame->copy_from(history[0]); \
912                 for(int k = 1; k < config.frames; k++) \
913                 { \
914                         VFrame *history_frame = history[k]; \
915  \
916                         for(int i = 0; i < h; i++) \
917                         { \
918                                 type *history_row = (type*)history_frame->get_rows()[i]; \
919                                 type *frame_row = (type*)frame->get_rows()[i]; \
920  \
921                                 for(int j = 0; j < w; j++) \
922                                 { \
923                                         int copy_it = 0; \
924 /* Compare alpha if 4 channel */ \
925                                         if(components == 4) \
926                                         { \
927                                                 if(history_row[3] < frame_row[3]) copy_it = 1; \
928                                         } \
929                                         else \
930                                         if(chroma) \
931                                         { \
932 /* Compare YUV luma if 3 channel */ \
933                                                 if(history_row[0] < frame_row[0]) copy_it = 1; \
934                                         } \
935                                         else \
936                                         { \
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])) \
940                                                         copy_it = 1; \
941                                         } \
942  \
943                                         if(copy_it) \
944                                         { \
945                                                 *frame_row++ = *history_row++; \
946                                                 *frame_row++ = *history_row++; \
947                                                 *frame_row++ = *history_row++; \
948                                                 if(components == 4) *frame_row++ = *history_row++; \
949                                         } \
950                                         else \
951                                         { \
952                                                 frame_row += components; \
953                                                 history_row += components; \
954                                         } \
955                                 } \
956                         } \
957                 } \
958         } \
959         else \
960         { \
961                 for(int i = 0; i < h; i++) \
962                 { \
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++) \
967                         { \
968                                 *frame_row++ = *accum_row++; \
969                                 *frame_row++ = *accum_row++; \
970                                 *frame_row++ = *accum_row++; \
971                                 if(components == 4) *frame_row++ = *accum_row++; \
972                         } \
973                 } \
974         } \
975 }
976
977
978 void TimeAvgMain::transfer_accum(VFrame *frame)
979 {
980         int w = frame->get_w();
981         int h = frame->get_h();
982
983         switch(frame->get_color_model())
984         {
985                 case BC_RGB888:
986                         TRANSFER_ACCUM(unsigned char, int, 3, 0x0, 0xff)
987                         break;
988                 case BC_RGB_FLOAT:
989                         TRANSFER_ACCUM(float, float, 3, 0x0, 1)
990                         break;
991                 case BC_RGBA8888:
992                         TRANSFER_ACCUM(unsigned char, int, 4, 0x0, 0xff)
993                         break;
994                 case BC_RGBA_FLOAT:
995                         TRANSFER_ACCUM(float, float, 4, 0x0, 1)
996                         break;
997                 case BC_YUV888:
998                         TRANSFER_ACCUM(unsigned char, int, 3, 0x80, 0xff)
999                         break;
1000                 case BC_YUVA8888:
1001                         TRANSFER_ACCUM(unsigned char, int, 4, 0x80, 0xff)
1002                         break;
1003                 case BC_YUV161616:
1004                         TRANSFER_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
1005                         break;
1006                 case BC_YUVA16161616:
1007                         TRANSFER_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
1008                         break;
1009         }
1010 }
1011
1012
1013
1014 int TimeAvgMain::load_configuration()
1015 {
1016         KeyFrame *prev_keyframe;
1017         TimeAvgConfig old_config;
1018         old_config.copy_from(&config);
1019
1020         prev_keyframe = get_prev_keyframe(get_source_position());
1021         read_data(prev_keyframe);
1022         return !old_config.equivalent(&config);
1023 }
1024
1025 void TimeAvgMain::save_data(KeyFrame *keyframe)
1026 {
1027         FileXML output;
1028
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.tag.set_title("/TIME_AVERAGE");
1040         output.append_tag();
1041         output.append_newline();
1042         output.terminate_string();
1043 }
1044
1045 void TimeAvgMain::read_data(KeyFrame *keyframe)
1046 {
1047         FileXML input;
1048
1049         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
1050
1051         while(!input.read_tag())
1052         {
1053                 if(input.tag.title_is("TIME_AVERAGE"))
1054                 {
1055                         config.frames = input.tag.get_property("FRAMES", config.frames);
1056                         config.mode = input.tag.get_property("MODE", config.mode);
1057                         config.paranoid = input.tag.get_property("PARANOID", config.paranoid);
1058                         config.nosubtract = input.tag.get_property("NOSUBTRACT", config.nosubtract);
1059                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
1060                         config.border = input.tag.get_property("BORDER", config.border);
1061                 }
1062         }
1063 }
1064
1065
1066 void TimeAvgMain::update_gui()
1067 {
1068         if(thread) 
1069         {
1070                 if(load_configuration())
1071                 {
1072                         thread->window->lock_window("TimeAvgMain::update_gui");
1073                         ((TimeAvgWindow*)thread->window)->total_frames->update(config.frames);
1074                         ((TimeAvgWindow*)thread->window)->threshold->update(config.threshold);
1075                         ((TimeAvgWindow*)thread->window)->update_toggles();
1076                         ((TimeAvgWindow*)thread->window)->paranoid->update(config.paranoid);
1077                         ((TimeAvgWindow*)thread->window)->no_subtract->update(config.nosubtract);
1078                         ((TimeAvgWindow*)thread->window)->threshold->update(config.threshold);
1079                         ((TimeAvgWindow*)thread->window)->border->update(config.border);
1080                         thread->window->unlock_window();
1081                 }
1082         }
1083 }
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093