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