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