update internationalization data
[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                                                 if(config.mode == TimeAvgConfig::AVERAGE ||
333                                                         config.mode == TimeAvgConfig::ACCUMULATE)
334                                                 {
335                                                         add_accum(history[j]);
336                                                 }
337                                                 break;
338                                         }
339                                 }
340                         }
341                 }
342                 delete [] new_history_frames;
343         }
344         else
345 // No history subtraction
346         {
347                 if(history)
348                 {
349                         for(int i = 0; i < config.frames; i++)
350                                 delete history[i];
351                         delete [] history;
352                         history = 0;
353                 }
354
355                 if(history_frame) delete [] history_frame;
356                 if(history_valid) delete [] history_valid;
357                 history_frame = 0;
358                 history_valid = 0;
359                 history_size = 0;
360
361 // Clamp prev_frame to history size
362                 prev_frame = MAX(start_position - config.frames + 1, prev_frame);
363
364 // Force reload if not repositioned or just started
365                 if( (config.paranoid && prev_frame == start_position) ||
366                         prev_frame < 0)
367                 {
368 //printf("TimeAvgMain::process_buffer %d\n", __LINE__);
369                         prev_frame = start_position - config.frames + 1;
370                         prev_frame = MAX(0, prev_frame);
371                         reset_accum(w, h, color_model);
372                 }
373
374 // printf("TimeAvgMain::process_buffer %d prev_frame=" _LD " start_position=" _LD "\n", 
375 //   __LINE__, prev_frame, start_position);
376                 for(int64_t i = prev_frame; i <= start_position; i++)
377                 {
378                         read_frame(frame,
379                                 0,
380                                 i,
381                                 frame_rate);
382                         add_accum(frame);
383 printf("TimeAvgMain::process_buffer %d prev_frame=" _LD " start_position=" _LD " i=" _LD "\n", 
384   __LINE__, prev_frame, start_position, i);
385                 }
386
387 // If we don't add 1, it rereads the frame again
388                 prev_frame = start_position + 1;
389         }
390
391
392
393
394
395
396
397 // Transfer accumulation to output with division if average is desired.
398         transfer_accum(frame);
399
400 //printf("TimeAvgMain::process_buffer %d\n", __LINE__);
401
402
403         return 0;
404 }
405
406
407
408
409
410
411
412
413
414
415 // Reset accumulation
416 #define SET_ACCUM(type, components, luma, chroma) \
417 { \
418         type *row = (type*)accumulation; \
419         if(chroma) \
420         { \
421                 for(int i = 0; i < w * h; i++) \
422                 { \
423                         *row++ = luma; \
424                         *row++ = chroma; \
425                         *row++ = chroma; \
426                         if(components == 4) *row++ = luma; \
427                 } \
428         } \
429         else \
430         { \
431                 bzero(row, w * h * sizeof(type) * components); \
432         } \
433 }
434
435
436 void TimeAvgMain::reset_accum(int w, int h, int color_model)
437 {
438         if(config.mode == TimeAvgConfig::LESS)
439         {
440                 switch(color_model)
441                 {
442                         case BC_RGB888:
443                                 SET_ACCUM(int, 3, 0xff, 0xff)
444                                 break;
445                         case BC_RGB_FLOAT:
446                                 SET_ACCUM(float, 3, 1.0, 1.0)
447                                 break;
448                         case BC_RGBA8888:
449                                 SET_ACCUM(int, 4, 0xff, 0xff)
450                                 break;
451                         case BC_RGBA_FLOAT:
452                                 SET_ACCUM(float, 4, 1.0, 1.0)
453                                 break;
454                         case BC_YUV888:
455                                 SET_ACCUM(int, 3, 0xff, 0x80)
456                                 break;
457                         case BC_YUVA8888:
458                                 SET_ACCUM(int, 4, 0xff, 0x80)
459                                 break;
460                         case BC_YUV161616:
461                                 SET_ACCUM(int, 3, 0xffff, 0x8000)
462                                 break;
463                         case BC_YUVA16161616:
464                                 SET_ACCUM(int, 4, 0xffff, 0x8000)
465                                 break;
466                 }
467         }
468         else
469         {
470                 switch(color_model)
471                 {
472                         case BC_RGB888:
473                                 SET_ACCUM(int, 3, 0x0, 0x0)
474                                 break;
475                         case BC_RGB_FLOAT:
476                                 SET_ACCUM(float, 3, 0x0, 0x0)
477                                 break;
478                         case BC_RGBA8888:
479                                 SET_ACCUM(int, 4, 0x0, 0x0)
480                                 break;
481                         case BC_RGBA_FLOAT:
482                                 SET_ACCUM(float, 4, 0x0, 0x0)
483                                 break;
484                         case BC_YUV888:
485                                 SET_ACCUM(int, 3, 0x0, 0x80)
486                                 break;
487                         case BC_YUVA8888:
488                                 SET_ACCUM(int, 4, 0x0, 0x80)
489                                 break;
490                         case BC_YUV161616:
491                                 SET_ACCUM(int, 3, 0x0, 0x8000)
492                                 break;
493                         case BC_YUVA16161616:
494                                 SET_ACCUM(int, 4, 0x0, 0x8000)
495                                 break;
496                 }
497         }
498 }
499
500 #define RGB_TO_VALUE(r, g, b) \
501 ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
502
503 // Only AVERAGE and ACCUMULATE use this
504 #define SUBTRACT_ACCUM(type, \
505         accum_type, \
506         components, \
507         chroma) \
508 { \
509         for(int i = 0; i < h; i++) \
510         { \
511                 accum_type *accum_row = (accum_type*)accumulation + \
512                         i * w * components; \
513                 type *frame_row = (type*)frame->get_rows()[i]; \
514                 for(int j = 0; j < w; j++) \
515                 { \
516                         *accum_row++ -= *frame_row++; \
517                         *accum_row++ -= (accum_type)*frame_row++ - chroma; \
518                         *accum_row++ -= (accum_type)*frame_row++ - chroma; \
519                         if(components == 4) *accum_row++ -= *frame_row++; \
520                 } \
521         } \
522 }
523
524
525 void TimeAvgMain::subtract_accum(VFrame *frame)
526 {
527 // Just accumulate
528         if(config.nosubtract) return;
529         int w = frame->get_w();
530         int h = frame->get_h();
531
532         switch(frame->get_color_model())
533         {
534                 case BC_RGB888:
535                         SUBTRACT_ACCUM(unsigned char, int, 3, 0x0)
536                         break;
537                 case BC_RGB_FLOAT:
538                         SUBTRACT_ACCUM(float, float, 3, 0x0)
539                         break;
540                 case BC_RGBA8888:
541                         SUBTRACT_ACCUM(unsigned char, int, 4, 0x0)
542                         break;
543                 case BC_RGBA_FLOAT:
544                         SUBTRACT_ACCUM(float, float, 4, 0x0)
545                         break;
546                 case BC_YUV888:
547                         SUBTRACT_ACCUM(unsigned char, int, 3, 0x80)
548                         break;
549                 case BC_YUVA8888:
550                         SUBTRACT_ACCUM(unsigned char, int, 4, 0x80)
551                         break;
552                 case BC_YUV161616:
553                         SUBTRACT_ACCUM(uint16_t, int, 3, 0x8000)
554                         break;
555                 case BC_YUVA16161616:
556                         SUBTRACT_ACCUM(uint16_t, int, 4, 0x8000)
557                         break;
558         }
559 }
560
561
562 // The behavior has to be very specific to the color model because we rely on
563 // the value of full black to determine what pixel to show.
564 #define ADD_ACCUM(type, accum_type, components, chroma, max) \
565 { \
566         if(config.mode == TimeAvgConfig::REPLACE) \
567         { \
568                 type threshold = config.threshold; \
569                 if(sizeof(type) == 4) \
570                         threshold /= 256; \
571 /* Compare all pixels if border */ \
572                 if(config.border > 0) \
573                 { \
574                         int border = config.border; \
575                         int h_border = h - border - 1; \
576                         int w_border = w - border - 1; \
577                         int kernel_size = (border * 2 + 1) * (border * 2 + 1); \
578                         for(int i = border; i < h_border; i++) \
579                         { \
580                                 for(int j = border; j < w_border; j++) \
581                                 { \
582                                         int copy_it = 0; \
583                                         for(int k = -border; k <= border; k++) \
584                                         { \
585                                                 type *frame_row = (type*)frame->get_rows()[i + k]; \
586                                                 for(int l = -border; l <= border; l++) \
587                                                 { \
588                                                         type *frame_pixel = frame_row + (j + l) * components; \
589 /* Compare alpha if 4 channel */ \
590                                                         if(components == 4) \
591                                                         { \
592                                                                 if(frame_pixel[3] > threshold) \
593                                                                         copy_it++; \
594                                                         } \
595                                                         else \
596                                                         if(sizeof(type) == 4) \
597                                                         { \
598 /* Compare luma if 3 channel */ \
599                                                                 if(RGB_TO_VALUE(frame_pixel[0], frame_pixel[1], frame_pixel[2]) >= \
600                                                                         threshold) \
601                                                                 { \
602                                                                         copy_it++; \
603                                                                 } \
604                                                         } \
605                                                         else \
606                                                         if(chroma) \
607                                                         { \
608                                                                 if(frame_pixel[0] >= threshold) \
609                                                                 { \
610                                                                         copy_it++; \
611                                                                 } \
612                                                         } \
613                                                         else \
614                                                         if(RGB_TO_VALUE(frame_pixel[0], frame_pixel[1], frame_pixel[2]) >= threshold) \
615                                                         { \
616                                                                 copy_it++; \
617                                                         } \
618                                                 } \
619                                         } \
620  \
621                                         if(copy_it == kernel_size) \
622                                         { \
623                                                 accum_type *accum_row = (accum_type*)accumulation + \
624                                                         i * w * components + j * components; \
625                                                 type *frame_row = (type*)frame->get_rows()[i] + j * components; \
626                                                 *accum_row++ = *frame_row++; \
627                                                 *accum_row++ = *frame_row++; \
628                                                 *accum_row++ = *frame_row++; \
629                                                 if(components == 4) *accum_row++ = *frame_row++; \
630                                         } \
631  \
632                                 } \
633                         } \
634                 } \
635                 else \
636 /* Compare only relevant pixel if no border */ \
637                 { \
638                         for(int i = 0; i < h; i++) \
639                         { \
640                                 accum_type *accum_row = (accum_type*)accumulation + \
641                                         i * w * components; \
642                                 type *frame_row = (type*)frame->get_rows()[i]; \
643                                 for(int j = 0; j < w; j++) \
644                                 { \
645                                         int copy_it = 0; \
646 /* Compare alpha if 4 channel */ \
647                                         if(components == 4) \
648                                         { \
649                                                 if(frame_row[3] > threshold) \
650                                                         copy_it = 1; \
651                                         } \
652                                         else \
653                                         if(sizeof(type) == 4) \
654                                         { \
655 /* Compare luma if 3 channel */ \
656                                                 if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) >= \
657                                                         threshold) \
658                                                 { \
659                                                         copy_it = 1; \
660                                                 } \
661                                         } \
662                                         else \
663                                         if(chroma) \
664                                         { \
665                                                 if(frame_row[0] >= threshold) \
666                                                 { \
667                                                         copy_it = 1; \
668                                                 } \
669                                         } \
670                                         else \
671                                         if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) >= threshold) \
672                                         { \
673                                                 copy_it = 1; \
674                                         } \
675  \
676                                         if(copy_it) \
677                                         { \
678                                                 *accum_row++ = *frame_row++; \
679                                                 *accum_row++ = *frame_row++; \
680                                                 *accum_row++ = *frame_row++; \
681                                                 if(components == 4) *accum_row++ = *frame_row++; \
682                                         } \
683                                         else \
684                                         { \
685                                                 frame_row += components; \
686                                                 accum_row += components; \
687                                         } \
688                                 } \
689                         } \
690                 } \
691         } \
692         else \
693         if(config.mode == TimeAvgConfig::GREATER) \
694         { \
695                 for(int i = 0; i < h; i++) \
696                 { \
697                         accum_type *accum_row = (accum_type*)accumulation + \
698                                 i * w * components; \
699                         type *frame_row = (type*)frame->get_rows()[i]; \
700                         for(int j = 0; j < w; j++) \
701                         { \
702                                 int copy_it = 0; \
703 /* Compare alpha if 4 channel */ \
704                                 if(components == 4) \
705                                 { \
706                                         if(frame_row[3] > accum_row[3]) copy_it = 1; \
707                                 } \
708                                 else \
709                                 if(chroma) \
710                                 { \
711 /* Compare YUV luma if 3 channel */ \
712                                         if(frame_row[0] > accum_row[0]) copy_it = 1; \
713                                 } \
714                                 else \
715                                 { \
716 /* Compare RGB luma if 3 channel */ \
717                                         if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) > \
718                                                 RGB_TO_VALUE(accum_row[0], accum_row[1], accum_row[2])) \
719                                                 copy_it = 1; \
720                                 } \
721  \
722                                 if(copy_it) \
723                                 { \
724                                         *accum_row++ = *frame_row++; \
725                                         *accum_row++ = *frame_row++; \
726                                         *accum_row++ = *frame_row++; \
727                                         if(components == 4) *accum_row++ = *frame_row++; \
728                                 } \
729                                 else \
730                                 { \
731                                         accum_row += components; \
732                                         frame_row += components; \
733                                 } \
734                         } \
735                 } \
736         } \
737         else \
738         if(config.mode == TimeAvgConfig::LESS) \
739         { \
740                 for(int i = 0; i < h; i++) \
741                 { \
742                         accum_type *accum_row = (accum_type*)accumulation + \
743                                 i * w * components; \
744                         type *frame_row = (type*)frame->get_rows()[i]; \
745                         for(int j = 0; j < w; j++) \
746                         { \
747                                 int copy_it = 0; \
748 /* Compare alpha if 4 channel */ \
749                                 if(components == 4) \
750                                 { \
751                                         if(frame_row[3] < accum_row[3]) copy_it = 1; \
752                                 } \
753                                 else \
754                                 if(chroma) \
755                                 { \
756 /* Compare YUV luma if 3 channel */ \
757                                         if(frame_row[0] < accum_row[0]) copy_it = 1; \
758                                 } \
759                                 else \
760                                 { \
761 /* Compare RGB luma if 3 channel */ \
762                                         if(RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2]) < \
763                                                 RGB_TO_VALUE(accum_row[0], accum_row[1], accum_row[2])) \
764                                                 copy_it = 1; \
765                                 } \
766  \
767                                 if(copy_it) \
768                                 { \
769                                         *accum_row++ = *frame_row++; \
770                                         *accum_row++ = *frame_row++; \
771                                         *accum_row++ = *frame_row++; \
772                                         if(components == 4) *accum_row++ = *frame_row++; \
773                                 } \
774                                 else \
775                                 { \
776                                         accum_row += components; \
777                                         frame_row += components; \
778                                 } \
779                         } \
780                 } \
781         } \
782         else \
783         { \
784                 for(int i = 0; i < h; i++) \
785                 { \
786                         accum_type *accum_row = (accum_type*)accumulation + \
787                                 i * w * components; \
788                         type *frame_row = (type*)frame->get_rows()[i]; \
789                         for(int j = 0; j < w; j++) \
790                         { \
791                                 *accum_row++ += *frame_row++; \
792                                 *accum_row++ += (accum_type)*frame_row++ - chroma; \
793                                 *accum_row++ += (accum_type)*frame_row++ - chroma; \
794                                 if(components == 4) *accum_row++ += *frame_row++; \
795                         } \
796                 } \
797         } \
798 }
799
800
801 void TimeAvgMain::add_accum(VFrame *frame)
802 {
803         int w = frame->get_w();
804         int h = frame->get_h();
805
806         switch(frame->get_color_model())
807         {
808                 case BC_RGB888:
809                         ADD_ACCUM(unsigned char, int, 3, 0x0, 0xff)
810                         break;
811                 case BC_RGB_FLOAT:
812                         ADD_ACCUM(float, float, 3, 0x0, 1.0)
813                         break;
814                 case BC_RGBA8888:
815                         ADD_ACCUM(unsigned char, int, 4, 0x0, 0xff)
816                         break;
817                 case BC_RGBA_FLOAT:
818                         ADD_ACCUM(float, float, 4, 0x0, 1.0)
819                         break;
820                 case BC_YUV888:
821                         ADD_ACCUM(unsigned char, int, 3, 0x80, 0xff)
822                         break;
823                 case BC_YUVA8888:
824                         ADD_ACCUM(unsigned char, int, 4, 0x80, 0xff)
825                         break;
826                 case BC_YUV161616:
827                         ADD_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
828                         break;
829                 case BC_YUVA16161616:
830                         ADD_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
831                         break;
832         }
833 }
834
835 #define TRANSFER_ACCUM(type, accum_type, components, chroma, max) \
836 { \
837         if(config.mode == TimeAvgConfig::AVERAGE) \
838         { \
839                 accum_type denominator = config.frames; \
840                 for(int i = 0; i < h; i++) \
841                 { \
842                         accum_type *accum_row = (accum_type*)accumulation + \
843                                 i * w * components; \
844                         type *frame_row = (type*)frame->get_rows()[i]; \
845                         for(int j = 0; j < w; j++) \
846                         { \
847                                 *frame_row++ = *accum_row++ / denominator; \
848                                 *frame_row++ = (*accum_row++ - chroma) / denominator + chroma; \
849                                 *frame_row++ = (*accum_row++ - chroma) / denominator + chroma; \
850                                 if(components == 4) *frame_row++ = *accum_row++ / denominator; \
851                         } \
852                 } \
853         } \
854         else \
855 /* Rescan history every time for these modes */ \
856         if(!config.nosubtract && config.mode == TimeAvgConfig::GREATER) \
857         { \
858                 frame->copy_from(history[0]); \
859                 for(int k = 1; k < config.frames; k++) \
860                 { \
861                         VFrame *history_frame = history[k]; \
862  \
863                         for(int i = 0; i < h; i++) \
864                         { \
865                                 type *history_row = (type*)history_frame->get_rows()[i]; \
866                                 type *frame_row = (type*)frame->get_rows()[i]; \
867  \
868                                 for(int j = 0; j < w; j++) \
869                                 { \
870                                         int copy_it = 0; \
871 /* Compare alpha if 4 channel */ \
872                                         if(components == 4) \
873                                         { \
874                                                 if(history_row[3] > frame_row[3]) copy_it = 1; \
875                                         } \
876                                         else \
877                                         if(chroma) \
878                                         { \
879 /* Compare YUV luma if 3 channel */ \
880                                                 if(history_row[0] > frame_row[0]) copy_it = 1; \
881                                         } \
882                                         else \
883                                         { \
884 /* Compare RGB luma if 3 channel */ \
885                                                 if(RGB_TO_VALUE(history_row[0], history_row[1], history_row[2]) > \
886                                                         RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2])) \
887                                                         copy_it = 1; \
888                                         } \
889  \
890                                         if(copy_it) \
891                                         { \
892                                                 *frame_row++ = *history_row++; \
893                                                 *frame_row++ = *history_row++; \
894                                                 *frame_row++ = *history_row++; \
895                                                 if(components == 4) *frame_row++ = *history_row++; \
896                                         } \
897                                         else \
898                                         { \
899                                                 frame_row += components; \
900                                                 history_row += components; \
901                                         } \
902                                 } \
903                         } \
904                 } \
905         } \
906         else \
907         if(!config.nosubtract && config.mode == TimeAvgConfig::LESS) \
908         { \
909                 frame->copy_from(history[0]); \
910                 for(int k = 1; k < config.frames; k++) \
911                 { \
912                         VFrame *history_frame = history[k]; \
913  \
914                         for(int i = 0; i < h; i++) \
915                         { \
916                                 type *history_row = (type*)history_frame->get_rows()[i]; \
917                                 type *frame_row = (type*)frame->get_rows()[i]; \
918  \
919                                 for(int j = 0; j < w; j++) \
920                                 { \
921                                         int copy_it = 0; \
922 /* Compare alpha if 4 channel */ \
923                                         if(components == 4) \
924                                         { \
925                                                 if(history_row[3] < frame_row[3]) copy_it = 1; \
926                                         } \
927                                         else \
928                                         if(chroma) \
929                                         { \
930 /* Compare YUV luma if 3 channel */ \
931                                                 if(history_row[0] < frame_row[0]) copy_it = 1; \
932                                         } \
933                                         else \
934                                         { \
935 /* Compare RGB luma if 3 channel */ \
936                                                 if(RGB_TO_VALUE(history_row[0], history_row[1], history_row[2]) < \
937                                                         RGB_TO_VALUE(frame_row[0], frame_row[1], frame_row[2])) \
938                                                         copy_it = 1; \
939                                         } \
940  \
941                                         if(copy_it) \
942                                         { \
943                                                 *frame_row++ = *history_row++; \
944                                                 *frame_row++ = *history_row++; \
945                                                 *frame_row++ = *history_row++; \
946                                                 if(components == 4) *frame_row++ = *history_row++; \
947                                         } \
948                                         else \
949                                         { \
950                                                 frame_row += components; \
951                                                 history_row += components; \
952                                         } \
953                                 } \
954                         } \
955                 } \
956         } \
957         else \
958         { \
959                 for(int i = 0; i < h; i++) \
960                 { \
961                         accum_type *accum_row = (accum_type*)accumulation + \
962                                 i * w * components; \
963                         type *frame_row = (type*)frame->get_rows()[i]; \
964                         for(int j = 0; j < w; j++) \
965                         { \
966                                 *frame_row++ = *accum_row++; \
967                                 *frame_row++ = *accum_row++; \
968                                 *frame_row++ = *accum_row++; \
969                                 if(components == 4) *frame_row++ = *accum_row++; \
970                         } \
971                 } \
972         } \
973 }
974
975
976 void TimeAvgMain::transfer_accum(VFrame *frame)
977 {
978         int w = frame->get_w();
979         int h = frame->get_h();
980
981         switch(frame->get_color_model())
982         {
983                 case BC_RGB888:
984                         TRANSFER_ACCUM(unsigned char, int, 3, 0x0, 0xff)
985                         break;
986                 case BC_RGB_FLOAT:
987                         TRANSFER_ACCUM(float, float, 3, 0x0, 1)
988                         break;
989                 case BC_RGBA8888:
990                         TRANSFER_ACCUM(unsigned char, int, 4, 0x0, 0xff)
991                         break;
992                 case BC_RGBA_FLOAT:
993                         TRANSFER_ACCUM(float, float, 4, 0x0, 1)
994                         break;
995                 case BC_YUV888:
996                         TRANSFER_ACCUM(unsigned char, int, 3, 0x80, 0xff)
997                         break;
998                 case BC_YUVA8888:
999                         TRANSFER_ACCUM(unsigned char, int, 4, 0x80, 0xff)
1000                         break;
1001                 case BC_YUV161616:
1002                         TRANSFER_ACCUM(uint16_t, int, 3, 0x8000, 0xffff)
1003                         break;
1004                 case BC_YUVA16161616:
1005                         TRANSFER_ACCUM(uint16_t, int, 4, 0x8000, 0xffff)
1006                         break;
1007         }
1008 }
1009
1010
1011
1012 int TimeAvgMain::load_configuration()
1013 {
1014         KeyFrame *prev_keyframe;
1015         TimeAvgConfig old_config;
1016         old_config.copy_from(&config);
1017
1018         prev_keyframe = get_prev_keyframe(get_source_position());
1019         read_data(prev_keyframe);
1020         return !old_config.equivalent(&config);
1021 }
1022
1023 void TimeAvgMain::save_data(KeyFrame *keyframe)
1024 {
1025         FileXML output;
1026
1027 // cause data to be stored directly in text
1028         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
1029         output.tag.set_title("TIME_AVERAGE");
1030         output.tag.set_property("FRAMES", config.frames);
1031         output.tag.set_property("MODE", config.mode);
1032         output.tag.set_property("PARANOID", config.paranoid);
1033         output.tag.set_property("NOSUBTRACT", config.nosubtract);
1034         output.tag.set_property("THRESHOLD", config.threshold);
1035         output.tag.set_property("BORDER", config.border);
1036         output.append_tag();
1037         output.terminate_string();
1038 }
1039
1040 void TimeAvgMain::read_data(KeyFrame *keyframe)
1041 {
1042         FileXML input;
1043
1044         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
1045
1046         while(!input.read_tag())
1047         {
1048                 if(input.tag.title_is("TIME_AVERAGE"))
1049                 {
1050                         config.frames = input.tag.get_property("FRAMES", config.frames);
1051                         config.mode = input.tag.get_property("MODE", config.mode);
1052                         config.paranoid = input.tag.get_property("PARANOID", config.paranoid);
1053                         config.nosubtract = input.tag.get_property("NOSUBTRACT", config.nosubtract);
1054                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
1055                         config.border = input.tag.get_property("BORDER", config.border);
1056                 }
1057         }
1058 }
1059
1060
1061 void TimeAvgMain::update_gui()
1062 {
1063         if(thread) 
1064         {
1065                 if(load_configuration())
1066                 {
1067                         thread->window->lock_window("TimeAvgMain::update_gui");
1068                         ((TimeAvgWindow*)thread->window)->total_frames->update(config.frames);
1069                         ((TimeAvgWindow*)thread->window)->threshold->update(config.threshold);
1070                         ((TimeAvgWindow*)thread->window)->update_toggles();
1071                         ((TimeAvgWindow*)thread->window)->paranoid->update(config.paranoid);
1072                         ((TimeAvgWindow*)thread->window)->no_subtract->update(config.nosubtract);
1073                         ((TimeAvgWindow*)thread->window)->threshold->update(config.threshold);
1074                         ((TimeAvgWindow*)thread->window)->border->update(config.border);
1075                         thread->window->unlock_window();
1076                 }
1077         }
1078 }
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088