Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / denoiseseltempavg / seltempavg.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "keyframe.h"
27 #include "language.h"
28 #include "seltempavg.h"
29 #include "seltempavgwindow.h"
30 #include "vframe.h"
31
32 #include <stdint.h>
33 #include <string.h>
34
35 REGISTER_PLUGIN(SelTempAvgMain)
36
37
38 //////////////////////////////////////////////////////////////////////
39 SelTempAvgConfig::SelTempAvgConfig()
40 {
41         frames = 1;
42         method = SelTempAvgConfig::METHOD_SELTEMPAVG;
43         offsetmode = SelTempAvgConfig::OFFSETMODE_RESTARTMARKERSYS;
44         paranoid = 0;
45         nosubtract = 0;
46         offset_restartmarker_keyframe = 0;
47         offset_fixed_value = -15;
48         gain = 1.00;
49
50         avg_threshold_RY = 0; avg_threshold_GU = 0; avg_threshold_BV = 0;
51         std_threshold_RY = 0; std_threshold_GU = 0; std_threshold_BV = 0;
52         mask_RY = 0; mask_GU = 0; mask_BV = 0;
53 }
54
55 void SelTempAvgConfig::copy_from(SelTempAvgConfig *src)
56 {
57         this->frames = src->frames;
58         this->method = src->method;
59         this->offsetmode = src->offsetmode;
60         this->paranoid = src->paranoid;
61         this->nosubtract = src->nosubtract;
62         this->offset_restartmarker_keyframe = src->offset_restartmarker_keyframe;
63         this->offset_fixed_value = src->offset_fixed_value;
64         this->gain = src->gain;
65         this->avg_threshold_RY = src->avg_threshold_RY; this->avg_threshold_GU = src->avg_threshold_GU;
66         this->avg_threshold_BV = src->avg_threshold_BV; this->std_threshold_RY = src->std_threshold_RY;
67         this->std_threshold_GU = src->std_threshold_GU; this->std_threshold_BV = src->std_threshold_BV;
68
69         this->mask_BV = src->mask_BV; this->mask_RY = src->mask_RY; this->mask_GU = src->mask_GU;
70 }
71
72 int SelTempAvgConfig::equivalent(SelTempAvgConfig *src)
73 {
74   return frames == src->frames &&
75           method == src->method &&
76           offsetmode == src->offsetmode &&
77           paranoid == src->paranoid &&
78           offset_restartmarker_keyframe == src->offset_restartmarker_keyframe &&
79           offset_fixed_value == src->offset_fixed_value &&
80           gain == src->gain &&
81           this->avg_threshold_RY == src->avg_threshold_RY && this->avg_threshold_GU == src->avg_threshold_GU &&
82           this->avg_threshold_BV == src->avg_threshold_BV && this->std_threshold_RY == src->std_threshold_RY &&
83           this->std_threshold_GU == src->std_threshold_GU && this->std_threshold_BV == src->std_threshold_BV &&
84           this->mask_RY == src->mask_RY && this->mask_GU == src->mask_GU && this->mask_BV == src->mask_BV;
85 }
86
87
88 //////////////////////////////////////////////////////////////////////
89 SelTempAvgMain::SelTempAvgMain(PluginServer *server)
90  : PluginVClient(server)
91 {
92
93         accumulation = 0;
94         history = 0;
95         history_size = 0;
96         history_start = -0x7fffffff;
97         history_frame = 0;
98         history_valid = 0;
99         prev_frame = -1;
100 }
101
102 SelTempAvgMain::~SelTempAvgMain()
103 {
104
105
106         if(accumulation)
107         {
108                 delete [] accumulation;
109                 delete [] accumulation_sq;
110         }
111         if(history)
112         {
113                 for(int i = 0; i < config.frames; i++)
114                         delete history[i];
115                 delete [] history;
116         }
117         if(history_frame) delete [] history_frame;
118         if(history_valid) delete [] history_valid;
119 }
120
121 const char* SelTempAvgMain::plugin_title() { return N_("Selective Temporal Averaging"); }
122 int SelTempAvgMain::is_realtime() { return 1; }
123
124
125 NEW_WINDOW_MACRO(SelTempAvgMain, SelTempAvgWindow);
126
127 int SelTempAvgMain::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         load_configuration();
135
136 // Allocate accumulation
137         if(!accumulation)
138         {
139                 accumulation = new unsigned char[w *
140                                                  h *
141                                                  BC_CModels::components(color_model) *
142                                                  sizeof(float)];
143
144                 accumulation_sq = new unsigned char[w *
145                                                     h *
146                                                     3 *
147                                                     sizeof(float)];
148                 clear_accum(w, h, color_model);
149         }
150
151         if(!config.nosubtract)
152         {
153 // Reallocate history
154                 if(history)
155                 {
156                         if(config.frames != history_size)
157                         {
158                                 VFrame **history2;
159                                 int64_t *history_frame2;
160                                 int *history_valid2;
161                                 history2 = new VFrame*[config.frames];
162                                 history_frame2 = new int64_t[config.frames];
163                                 history_valid2 = new int[config.frames];
164
165 // Copy existing frames over
166                                 int i, j;
167                                 for(i = 0, j = 0; i < config.frames && j < history_size; i++, j++)
168                                 {
169                                         history2[i] = history[j];
170                                         history_frame2[i] = history_frame[i];
171                                         history_valid2[i] = history_valid[i];
172                                 }
173
174 // Delete extra previous frames and subtract from accumulation
175                                 for( ; j < history_size; j++)
176                                 {
177                                         subtract_accum(history[j]);
178                                         delete history[j];
179                                 }
180                                 delete [] history;
181                                 delete [] history_frame;
182                                 delete [] history_valid;
183
184
185 // Create new frames
186                                 for( ; i < config.frames; i++)
187                                 {
188                                         history2[i] = new VFrame(w, h, color_model, 0);
189                                         history_frame2[i] = -0x7fffffff;
190                                         history_valid2[i] = 0;
191                                 }
192
193                                 history = history2;
194                                 history_frame = history_frame2;
195                                 history_valid = history_valid2;
196
197                                 history_size = config.frames;
198                         }
199                 }
200                 else
201 // Allocate history
202                 {
203                         history = new VFrame*[config.frames];
204                         for(int i = 0; i < config.frames; i++)
205                                 history[i] = new VFrame(w, h, color_model, 0);
206                         history_size = config.frames;
207                         history_frame = new int64_t[config.frames];
208                         bzero(history_frame, sizeof(int64_t) * config.frames);
209                         history_valid = new int[config.frames];
210                         bzero(history_valid, sizeof(int) * config.frames);
211                 }
212
213
214
215
216
217
218 // Create new history frames based on current frame
219                 int64_t *new_history_frames = new int64_t[history_size];
220
221                 int64_t theoffset = (int64_t) config.offset_fixed_value;
222                 if (config.offsetmode == SelTempAvgConfig::OFFSETMODE_RESTARTMARKERSYS)
223                         theoffset = (int64_t) restartoffset;
224
225                 for(int i = 0; i < history_size; i++)
226                 {
227                         new_history_frames[history_size - i - 1] = start_position + theoffset + i;
228                 }
229
230 // Subtract old history frames which are not in the new vector
231                 int no_change = 1;
232                 for(int i = 0; i < history_size; i++)
233                 {
234 // Old frame is valid
235                         if(history_valid[i])
236                         {
237                                 int got_it = 0;
238                                 for(int j = 0; j < history_size; j++)
239                                 {
240 // Old frame is equal to a new frame
241                                         if(history_frame[i] == new_history_frames[j])
242                                         {
243                                                 got_it = 1;
244                                                 break;
245                                         }
246                                 }
247
248 // Didn't find old frame in new frames
249                                 if(!got_it)
250                                 {
251                                         subtract_accum(history[i]);
252                                         history_valid[i] = 0;
253                                         no_change = 0;
254                                 }
255                         }
256                 }
257 // If all frames are still valid, assume tweek occurred upstream and reload.
258                 if(config.paranoid && no_change)
259                 {
260                         for(int i = 0; i < history_size; i++)
261                         {
262                                 history_valid[i] = 0;
263                         }
264                         clear_accum(w, h, color_model);
265                 }
266
267 // Add new history frames which are not in the old vector
268                 for(int i = 0; i < history_size; i++)
269                 {
270 // Find new frame in old vector
271                         int got_it = 0;
272                         for(int j = 0; j < history_size; j++)
273                         {
274                                 if(history_valid[j] && history_frame[j] == new_history_frames[i])
275                                 {
276                                         got_it = 1;
277                                         break;
278                                 }
279                         }
280
281 // Didn't find new frame in old vector
282                         if(!got_it)
283                         {
284 // Get first unused entry
285                                 for(int j = 0; j < history_size; j++)
286                                 {
287                                         if(!history_valid[j])
288                                         {
289 // Load new frame into it
290                                                 history_frame[j] = new_history_frames[i];
291                                                 history_valid[j] = 1;
292                                                 read_frame(history[j],
293                                                         0,
294                                                         history_frame[j],
295                                                         frame_rate,
296                                                         0);
297                                                 add_accum(history[j]);
298                                                 break;
299                                         }
300                                 }
301                         }
302                 }
303                 delete [] new_history_frames;
304         }
305         else
306 // No subtraction
307         {
308 // Force reload if not repositioned or just started
309                 if( (config.paranoid && prev_frame == start_position) ||
310                         prev_frame < 0 )
311                 {
312                         prev_frame = start_position - config.frames + 1;
313                         prev_frame = MAX(0, prev_frame);
314                         clear_accum(w, h, color_model);
315                 }
316
317                 for(int64_t i = prev_frame; i <= start_position; i++)
318                 {
319                         read_frame(frame,
320                                 0,
321                                 i,
322                                 frame_rate,
323                                 0);
324                         add_accum(frame);
325 //printf("SelTempAvgMain::process_buffer 1 %lld %lld %lld\n", prev_frame, start_position, i);
326                 }
327
328                 prev_frame = start_position;
329         }
330
331
332
333         // Read current frame into buffer (needed for the std-deviation tool)
334         read_frame(frame,
335                         0,
336                         start_position,
337                         frame_rate,
338                         0);
339
340
341 // Transfer accumulation to output with division if average is desired.
342         transfer_accum(frame);
343
344 //printf("SelTempAvgMain::process_buffer 2\n");
345
346
347         return 0;
348 }
349
350
351
352
353
354
355
356
357
358
359 // Reset accumulation
360 #define CLEAR_ACCUM(type, components, chroma) \
361 { \
362         float *row = (float*)accumulation; \
363         float *row_sq = (float*)accumulation_sq; \
364         if(chroma) \
365         { \
366                 for(int i = 0; i < w * h; i++) \
367                 { \
368                         *row++ = 0x0; \
369                         *row++ = 0x0; \
370                         *row++ = 0x0; \
371                         if(components == 4) *row++ = 0x0; \
372                         *row_sq++ = 0x0; \
373                         *row_sq++ = 0x0; \
374                         *row_sq++ = 0x0; \
375                 } \
376         } \
377         else \
378         { \
379                 bzero(row, w * h * sizeof(type) * components); \
380                 bzero(row_sq, w * h * 3 * sizeof(float)); \
381         } \
382 }
383
384
385 void SelTempAvgMain::clear_accum(int w, int h, int color_model)
386 {
387         switch(color_model)
388         {
389                 case BC_RGB888:
390                         CLEAR_ACCUM(int, 3, 0x0)
391                         break;
392                 case BC_RGB_FLOAT:
393                         CLEAR_ACCUM(float, 3, 0x0)
394                         break;
395                 case BC_RGBA8888:
396                         CLEAR_ACCUM(int, 4, 0x0)
397                         break;
398                 case BC_RGBA_FLOAT:
399                         CLEAR_ACCUM(float, 4, 0x0)
400                         break;
401                 case BC_YUV888:
402                         CLEAR_ACCUM(int, 3, 0x80)
403                         break;
404                 case BC_YUVA8888:
405                         CLEAR_ACCUM(int, 4, 0x80)
406                         break;
407                 case BC_YUV161616:
408                         CLEAR_ACCUM(int, 3, 0x8000)
409                         break;
410                 case BC_YUVA16161616:
411                         CLEAR_ACCUM(int, 4, 0x8000)
412                         break;
413         }
414 }
415 #define C2_IS(frame_row,chroma,max)  (float)(frame_row)/max
416
417
418 #define SUBTRACT_ACCUM(type, \
419         components, \
420         chroma, \
421         max) \
422 { \
423         if(1) \
424         { \
425                 for(int i = 0; i < h; i++) \
426                 { \
427                         float *accum_row = (float*)accumulation + \
428                                 i * w * components; \
429                         float *accum_row_sq = (float*)accumulation_sq + \
430                                 i * w *3; \
431                         type *frame_row = (type*)frame->get_rows()[i]; \
432                         float c1, c2, c3; \
433                         for(int j = 0; j < w; j++) \
434                         { \
435                                 c1 = ( (float)*frame_row )/max; \
436                                 frame_row++; \
437                                 c2 = ( (float)*frame_row )/max; \
438                                 frame_row++; \
439                                 c3 = ( (float)(*frame_row -0) )/max; \
440                                 frame_row++; \
441 \
442                                 *accum_row -= c1; \
443                                 accum_row++; \
444                                 *accum_row -= c2; \
445                                 accum_row++; \
446                                 *accum_row -= c3; \
447                                 accum_row++; \
448                                 if(components == 4) { *accum_row -= ((float)*frame_row++)/max; accum_row++; } \
449 \
450                                 *accum_row_sq++ -= c1*c1; \
451                                 *accum_row_sq++ -= c2*c2; \
452                                 *accum_row_sq++ -= c3*c3; \
453                         } \
454                 } \
455         } \
456 }
457
458
459 void SelTempAvgMain::subtract_accum(VFrame *frame)
460 {
461 // Just accumulate
462         if(config.nosubtract) return;
463         int w = frame->get_w();
464         int h = frame->get_h();
465
466         switch(frame->get_color_model())
467         {
468                 case BC_RGB888:
469                         SUBTRACT_ACCUM(unsigned char, 3, 0x0, 0xff)
470                         break;
471                 case BC_RGB_FLOAT:
472                         SUBTRACT_ACCUM(float, 3, 0x0, 1.0)
473                         break;
474                 case BC_RGBA8888:
475                         SUBTRACT_ACCUM(unsigned char, 4, 0x0, 0xff)
476                         break;
477                 case BC_RGBA_FLOAT:
478                         SUBTRACT_ACCUM(float, 4, 0x0, 1.0)
479                         break;
480                 case BC_YUV888:
481                         SUBTRACT_ACCUM(unsigned char, 3, 0x80, 0xff)
482                         break;
483                 case BC_YUVA8888:
484                         SUBTRACT_ACCUM(unsigned char, 4, 0x80, 0xff)
485                         break;
486                 case BC_YUV161616:
487                         SUBTRACT_ACCUM(uint16_t, 3, 0x8000, 0xffff)
488                         break;
489                 case BC_YUVA16161616:
490                         SUBTRACT_ACCUM(uint16_t, 4, 0x8000, 0xffff)
491                         break;
492         }
493 }
494
495
496 // The behavior has to be very specific to the color model because we rely on
497 // the value of full black to determine what pixel to show.
498 #define ADD_ACCUM(type, components, chroma, max) \
499 { \
500         float c1, c2, c3; \
501         if(1) \
502         { \
503                 for(int i = 0; i < h; i++) \
504                 { \
505                         float *accum_row = (float*)accumulation + \
506                                 i * w * components; \
507                         float *accum_row_sq = (float*)accumulation_sq + \
508                                 i * w *3; \
509                         type *frame_row = (type*)frame->get_rows()[i]; \
510                         for(int j = 0; j < w; j++) \
511                         { \
512                                 c1 = ( (float)*frame_row )/max; \
513                                 frame_row++; \
514                                 c2 = ( (float)*frame_row )/max; \
515                                 frame_row++; \
516                                 c3 = ( (float)*frame_row )/max; \
517                                 frame_row++; \
518 \
519                                 *accum_row += c1; \
520                                 accum_row++; \
521                                 *accum_row += c2; \
522                                 accum_row++; \
523                                 *accum_row += c3; \
524                                 accum_row++; \
525                                 if(components == 4) { *accum_row += ((float)*frame_row++)/max; accum_row++; } \
526 \
527                                 *accum_row_sq++ += c1*c1; \
528                                 *accum_row_sq++ += c2*c2; \
529                                 *accum_row_sq++ += c3*c3; \
530                         } \
531                 } \
532         } \
533 }
534
535
536 void SelTempAvgMain::add_accum(VFrame *frame)
537 {
538         int w = frame->get_w();
539         int h = frame->get_h();
540
541         switch(frame->get_color_model())
542         {
543                 case BC_RGB888:
544                         ADD_ACCUM(unsigned char, 3, 0x0, 0xff)
545                         break;
546                 case BC_RGB_FLOAT:
547                         ADD_ACCUM(float, 3, 0x0, 1.0)
548                         break;
549                 case BC_RGBA8888:
550                         ADD_ACCUM(unsigned char, 4, 0x0, 0xff)
551                         break;
552                 case BC_RGBA_FLOAT:
553                         ADD_ACCUM(float, 4, 0x0, 1.0)
554                         break;
555                 case BC_YUV888:
556                         ADD_ACCUM(unsigned char, 3, 0x80, 0xff)
557                         break;
558                 case BC_YUVA8888:
559                         ADD_ACCUM(unsigned char, 4, 0x80, 0xff)
560                         break;
561                 case BC_YUV161616:
562                         ADD_ACCUM(uint16_t, 3, 0x8000, 0xffff)
563                         break;
564                 case BC_YUVA16161616:
565                         ADD_ACCUM(uint16_t, 4, 0x8000, 0xffff)
566                         break;
567         }
568 }
569
570 #define MASKER(type, avg_thresh, std_thresh, c_now, c_mean, c_stddev, mask, gain, frame_rowp, max) \
571 { \
572       if ( (avg_thresh > fabs(c_now - c_mean)) &&  (std_thresh > c_stddev) ) \
573              if (mask) \
574                    frame_rowp = max; \
575              else \
576                    frame_rowp = (type)(c_mean*max*gain); \
577       else \
578              if (mask) \
579                    frame_rowp = 0; \
580              else \
581                    frame_rowp = (type)(c_now*max*gain); \
582 }
583
584 #define TRANSFER_ACCUM(type, components, chroma, max, c1_gain, c2_gain, c3_gain) \
585 { \
586         if(config.method == SelTempAvgConfig::METHOD_SELTEMPAVG) \
587         { \
588                 float denominator = config.frames; \
589                 float c1_now, c2_now, c3_now; \
590                 float c1_mean, c2_mean, c3_mean; \
591                 float c1_stddev, c2_stddev, c3_stddev; \
592                 for(int i = 0; i < h; i++) \
593                 { \
594                         float *accum_row = (float*)accumulation + i * w * components; \
595                         float *accum_row_sq = (float*)accumulation_sq + i * w * 3; \
596 \
597                         type *frame_row = (type*)frame->get_rows()[i]; \
598                         for(int j = 0; j < w; j++) \
599                         { \
600                                 c1_now = (float)(*frame_row)/max; \
601                                 frame_row++; \
602                                 c2_now = (float)(*frame_row)/max; \
603                                 frame_row++; \
604                                 c3_now = (float)(*frame_row)/max; \
605                                 frame_row -= 2; \
606 \
607                                 c1_mean = *accum_row/denominator; \
608                                 accum_row++; \
609                                 c2_mean = *accum_row/denominator; \
610                                 accum_row++; \
611                                 c3_mean = *accum_row/denominator; \
612                                 accum_row++; \
613                                 if(components == 4) { accum_row++; } \
614 \
615                                 c1_stddev = (*accum_row_sq++)/denominator - c1_mean*c1_mean; \
616                                 c2_stddev = (*accum_row_sq++)/denominator - c2_mean*c2_mean; \
617                                 c3_stddev = (*accum_row_sq++)/denominator - c3_mean*c3_mean; \
618 \
619                                 MASKER(type,  \
620                                        config.avg_threshold_RY, \
621                                        config.std_threshold_RY, \
622                                        c1_now, c1_mean, c1_stddev, config.mask_RY, c1_gain,\
623                                        *frame_row++, max)\
624                                 MASKER(type,  \
625                                        config.avg_threshold_GU, \
626                                        config.std_threshold_GU, \
627                                        c2_now, c2_mean, c2_stddev, config.mask_GU, c2_gain,\
628                                        *frame_row++, max)\
629                                 MASKER(type,  \
630                                        config.avg_threshold_BV, \
631                                        config.std_threshold_BV, \
632                                        c3_now, c3_mean, c3_stddev, config.mask_BV, c3_gain,\
633                                        *frame_row++, max)\
634                                 if(components == 4)  *frame_row++ = max; \
635                         } \
636                 } \
637         } \
638         else \
639         if(config.method == SelTempAvgConfig::METHOD_AVERAGE) \
640         { \
641                 float denominator = config.frames; \
642                 for(int i = 0; i < h; i++) \
643                 { \
644                         float *accum_row = (float*)accumulation + i * w * components; \
645                         type *frame_row = (type*)frame->get_rows()[i]; \
646                         for(int j = 0; j < w; j++) \
647                         { \
648 \
649                                 *frame_row++ = (type)( (*accum_row++ / denominator)*c1_gain*max ); \
650                                 *frame_row++ = (type)( (*accum_row++ / denominator)*c2_gain*max ); \
651                                 *frame_row++ = (type)( (*accum_row++ / denominator)*c3_gain*max ); \
652                                 if(components == 4) *frame_row++ = (type)((*accum_row++/denominator)*max ); \
653                         } \
654                 } \
655         } \
656         else \
657         if(config.method == SelTempAvgConfig::METHOD_STDDEV) \
658         { \
659                 float c1_mean, c2_mean, c3_mean; \
660                 float c1_stddev, c2_stddev, c3_stddev; \
661                 float denominator = config.frames; \
662                 for(int i = 0; i < h; i++) \
663                 { \
664                         float *accum_row = (float*)accumulation + i * w * components; \
665                         float *accum_row_sq = (float*)accumulation_sq + i * w * 3; \
666                         type *frame_row = (type*)frame->get_rows()[i]; \
667                         for(int j = 0; j < w; j++) \
668                         { \
669 \
670                                 c1_mean = *accum_row/denominator; \
671                                 accum_row++; \
672                                 c2_mean = *accum_row/denominator; \
673                                 accum_row++; \
674                                 c3_mean = *accum_row/denominator; \
675                                 accum_row++; \
676                                 if(components == 4) { accum_row++; } \
677 \
678                                 c1_stddev = (*accum_row_sq++)/denominator - c1_mean*c1_mean; \
679                                 c2_stddev = (*accum_row_sq++)/denominator - c2_mean*c2_mean; \
680                                 c3_stddev = (*accum_row_sq++)/denominator - c3_mean*c3_mean; \
681 \
682                                 *frame_row++ = (type)( c1_stddev*c1_gain*max ); \
683                                 *frame_row++ = (type)( c2_stddev*c2_gain*max ); \
684                                 *frame_row++ = (type)( c3_stddev*c3_gain*max ); \
685                                 if(components == 4) *frame_row++ = max; \
686                         } \
687                 } \
688         } \
689 }
690
691
692 void SelTempAvgMain::transfer_accum(VFrame *frame)
693 {
694         int w = frame->get_w();
695         int h = frame->get_h();
696
697         switch(frame->get_color_model())
698         {
699                 case BC_RGB888:
700                         TRANSFER_ACCUM(unsigned char, 3  , 0x0   , 0xff  , config.gain, config.gain, config.gain)
701                         break;
702                 case BC_RGB_FLOAT:
703                         TRANSFER_ACCUM(float        , 3  , 0x0   , 1     , config.gain, config.gain, config.gain)
704                         break;
705                 case BC_RGBA8888:
706                         TRANSFER_ACCUM(unsigned char, 4  , 0x0   , 0xff  , config.gain, config.gain, config.gain)
707                         break;
708                 case BC_RGBA_FLOAT:
709                         TRANSFER_ACCUM(float        , 4  , 0x0   , 1     , config.gain, config.gain, config.gain)
710                         break;
711                 case BC_YUV888:
712                         TRANSFER_ACCUM(unsigned char, 3  , 0x80  , 0xff  , config.gain, 1.0        , 1.0)
713                         break;
714                 case BC_YUVA8888:
715                         TRANSFER_ACCUM(unsigned char, 4  , 0x80  , 0xff  , config.gain, 1.0        , 1.0)
716                         break;
717                 case BC_YUV161616:
718                         TRANSFER_ACCUM(uint16_t     , 3  , 0x8000, 0xffff, config.gain, 1.0        , 1.0)
719                         break;
720                 case BC_YUVA16161616:
721                         TRANSFER_ACCUM(uint16_t     , 4  , 0x8000, 0xffff, config.gain, 1.0        , 1.0)
722                         break;
723         }
724 }
725
726
727
728 int SelTempAvgMain::load_configuration()
729 {
730         KeyFrame *prev_keyframe;
731         KeyFrame *temp_keyframe;
732
733         SelTempAvgConfig old_config;
734         old_config.copy_from(&config);
735
736         int64_t curpos = get_source_position();
737         prev_keyframe = get_prev_keyframe(curpos);
738         read_data(prev_keyframe);
739
740         if (curpos == prev_keyframe->position)
741                 onakeyframe = 1;
742         else
743                 onakeyframe = 0;
744
745         int64_t next_restart_keyframe     = curpos + config.frames;
746         int64_t prev_restart_keyframe     = curpos - config.frames;
747
748         for (int i = curpos; i < curpos + config.frames; i++)
749         {
750                 temp_keyframe = get_next_keyframe(i);
751                 if (
752                         (temp_keyframe->position < curpos + config.frames/2) &&
753                         (temp_keyframe->position > curpos) &&
754                         nextkeyframeisoffsetrestart(temp_keyframe)
755                         )
756                 {
757                         next_restart_keyframe = temp_keyframe->position;
758                         i = curpos + config.frames;
759                 } else if (temp_keyframe->position > i)
760                         i = temp_keyframe->position;
761         }
762
763         for (int i = curpos; i > curpos - config.frames; i--)
764         {
765                 temp_keyframe = get_prev_keyframe(i);
766                 if (
767                         (temp_keyframe->position > curpos - config.frames/2) &&
768                         (temp_keyframe->position < curpos) &&
769                         nextkeyframeisoffsetrestart(temp_keyframe)
770                         )
771                 {
772                         prev_restart_keyframe = temp_keyframe->position;
773                         i = curpos - config.frames;
774                 } else if (temp_keyframe->position < i)
775                         i = temp_keyframe->position;
776         }
777
778         restartoffset = -config.frames/2;
779
780         if (onakeyframe && config.offset_restartmarker_keyframe)
781                 restartoffset = 0;
782         else if ((curpos - prev_restart_keyframe) < config.frames/2)
783                 restartoffset = prev_restart_keyframe - curpos;
784         else if ((next_restart_keyframe - curpos) < config.frames/2) {
785                 restartoffset = (next_restart_keyframe - curpos) - config.frames;
786                 // Probably should put another if in here, (when two "restart" keyframes are close together
787         }
788
789         return !old_config.equivalent(&config);
790 }
791
792 void SelTempAvgMain::save_data(KeyFrame *keyframe)
793 {
794         FileXML output;
795
796 // cause data to be stored directly in text
797         output.set_shared_output(keyframe->xbuf);
798         output.tag.set_title("SELECTIVE_TEMPORAL_AVERAGE");
799         output.tag.set_property("FRAMES", config.frames);
800         output.tag.set_property("METHOD", config.method);
801         output.tag.set_property("OFFSETMODE", config.offsetmode);
802         output.tag.set_property("PARANOID", config.paranoid);
803         output.tag.set_property("NOSUBTRACT", config.nosubtract);
804         output.tag.set_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe);
805         output.tag.set_property("OFFSETMODE_FIXED_VALUE", config.offset_fixed_value);
806         output.tag.set_property("GAIN", config.gain);
807
808
809         output.tag.set_property("AVG_THRESHOLD_RY", config.avg_threshold_RY);
810         output.tag.set_property("AVG_THRESHOLD_GU", config.avg_threshold_GU);
811         output.tag.set_property("AVG_THRESHOLD_BV", config.avg_threshold_BV);
812         output.tag.set_property("STD_THRESHOLD_RY", config.std_threshold_RY);
813         output.tag.set_property("STD_THRESHOLD_GU", config.std_threshold_GU);
814         output.tag.set_property("STD_THRESHOLD_BV", config.std_threshold_BV);
815
816         output.tag.set_property("MASK_RY", config.mask_RY);
817         output.tag.set_property("MASK_GU", config.mask_GU);
818         output.tag.set_property("MASK_BV", config.mask_BV);
819
820         output.append_tag();
821         output.tag.set_title("/SELECTIVE_TEMPORAL_AVERAGE");
822         output.append_tag();
823         output.append_newline();
824         output.terminate_string();
825 }
826
827 void SelTempAvgMain::read_data(KeyFrame *keyframe)
828 {
829         FileXML input;
830
831         input.set_shared_input(keyframe->xbuf);
832
833         while(!input.read_tag())
834         {
835                 if(input.tag.title_is("SELECTIVE_TEMPORAL_AVERAGE"))
836                 {
837                         config.frames = input.tag.get_property("FRAMES", config.frames);
838                         config.method = input.tag.get_property("METHOD", config.method);
839                         config.offsetmode = input.tag.get_property("OFFSETMODE", config.offsetmode);
840                         config.paranoid = input.tag.get_property("PARANOID", config.paranoid);
841                         config.nosubtract = input.tag.get_property("NOSUBTRACT", config.nosubtract);
842                         config.offset_restartmarker_keyframe = input.tag.get_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe);
843                         config.offset_fixed_value = input.tag.get_property("OFFSETMODE_FIXED_VALUE", config.offset_fixed_value);
844                         config.gain = input.tag.get_property("gain", config.gain);
845
846                         config.avg_threshold_RY = input.tag.get_property("AVG_THRESHOLD_RY", config.avg_threshold_RY);
847                         config.avg_threshold_GU = input.tag.get_property("AVG_THRESHOLD_GU", config.avg_threshold_GU);
848                         config.avg_threshold_BV = input.tag.get_property("AVG_THRESHOLD_BV", config.avg_threshold_BV);
849                         config.std_threshold_RY = input.tag.get_property("STD_THRESHOLD_RY", config.std_threshold_RY);
850                         config.std_threshold_GU = input.tag.get_property("STD_THRESHOLD_GU", config.std_threshold_GU);
851                         config.std_threshold_BV = input.tag.get_property("STD_THRESHOLD_BV", config.std_threshold_BV);
852
853                         config.mask_RY = input.tag.get_property("MASK_RY", config.mask_RY);
854                         config.mask_GU = input.tag.get_property("MASK_GU", config.mask_GU);
855                         config.mask_BV = input.tag.get_property("MASK_BV", config.mask_BV);
856
857                 }
858         }
859 }
860
861
862
863 int SelTempAvgMain::nextkeyframeisoffsetrestart(KeyFrame *keyframe)
864 {
865         FileXML input;
866
867         input.set_shared_input(keyframe->xbuf);
868
869         while(!input.read_tag())
870         {
871                 if(input.tag.title_is("SELECTIVE_TEMPORAL_AVERAGE"))
872                 {
873                         return(input.tag.get_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe));
874                 }
875         }
876         return (0);
877 }
878
879
880
881 void SelTempAvgMain::update_gui()
882 {
883         if(thread)
884         {
885                 ((SelTempAvgWindow*)thread->window)->lock_window("SelTempAvgMain::update_gui");
886                 if(load_configuration())
887                 {
888                         ((SelTempAvgWindow*)thread->window)->total_frames->update(config.frames);
889
890                         ((SelTempAvgWindow*)thread->window)->method_none->update(         config.method == SelTempAvgConfig::METHOD_NONE);
891                         ((SelTempAvgWindow*)thread->window)->method_seltempavg->update(   config.method == SelTempAvgConfig::METHOD_SELTEMPAVG);
892                         ((SelTempAvgWindow*)thread->window)->method_average->update(      config.method == SelTempAvgConfig::METHOD_AVERAGE);
893                         ((SelTempAvgWindow*)thread->window)->method_stddev->update(       config.method == SelTempAvgConfig::METHOD_STDDEV);
894
895                         ((SelTempAvgWindow*)thread->window)->offset_fixed->update(        config.offsetmode == SelTempAvgConfig::OFFSETMODE_FIXED);
896                         ((SelTempAvgWindow*)thread->window)->offset_restartmarker->update(config.offsetmode == SelTempAvgConfig::OFFSETMODE_RESTARTMARKERSYS);
897
898
899                         ((SelTempAvgWindow*)thread->window)->paranoid->update(config.paranoid);
900                         ((SelTempAvgWindow*)thread->window)->no_subtract->update(config.nosubtract);
901
902                         ((SelTempAvgWindow*)thread->window)->offset_fixed_value->update((int64_t)config.offset_fixed_value);
903                         ((SelTempAvgWindow*)thread->window)->gain->update(config.gain);
904
905                         ((SelTempAvgWindow*)thread->window)->avg_threshold_RY->update((float)config.avg_threshold_RY);
906                         ((SelTempAvgWindow*)thread->window)->avg_threshold_GU->update((float)config.avg_threshold_GU);
907                         ((SelTempAvgWindow*)thread->window)->avg_threshold_BV->update((float)config.avg_threshold_BV);
908                         ((SelTempAvgWindow*)thread->window)->std_threshold_RY->update((float)config.std_threshold_RY);
909                         ((SelTempAvgWindow*)thread->window)->std_threshold_GU->update((float)config.std_threshold_GU);
910                         ((SelTempAvgWindow*)thread->window)->std_threshold_BV->update((float)config.std_threshold_BV);
911
912                         ((SelTempAvgWindow*)thread->window)->mask_RY->update(config.mask_RY);
913                         ((SelTempAvgWindow*)thread->window)->mask_GU->update(config.mask_GU);
914                         ((SelTempAvgWindow*)thread->window)->mask_BV->update(config.mask_BV);
915                 }
916                 ((SelTempAvgWindow*)thread->window)->offset_restartmarker_pos->update((int64_t)restartoffset);
917                 ((SelTempAvgWindow*)thread->window)->offset_restartmarker_keyframe->update((config.offset_restartmarker_keyframe) && (onakeyframe));
918                 ((SelTempAvgWindow*)thread->window)->unlock_window();
919         }
920 }
921
922
923
924
925
926
927
928
929
930