booby fixes, seltemp radio btn offset fix, ffmpeg options layout tweak, change extens...
[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  *
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 = -15;
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 N_("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, 0);
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, 0);
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                                                         0);
296                                                 add_accum(history[j]);
297                                                 break;
298                                         }
299                                 }
300                         }
301                 }
302                 delete [] new_history_frames;
303         }
304         else
305 // No subtraction
306         {
307 // Force reload if not repositioned or just started
308                 if( (config.paranoid && prev_frame == start_position) ||
309                         prev_frame < 0 )
310                 {
311                         prev_frame = start_position - config.frames + 1;
312                         prev_frame = MAX(0, prev_frame);
313                         clear_accum(w, h, color_model);
314                 }
315
316                 for(int64_t i = prev_frame; i <= start_position; i++)
317                 {
318                         read_frame(frame,
319                                 0,
320                                 i,
321                                 frame_rate,
322                                 0);
323                         add_accum(frame);
324 //printf("SelTempAvgMain::process_buffer 1 %lld %lld %lld\n", prev_frame, start_position, i);
325                 }
326
327                 prev_frame = start_position;
328         }
329
330
331
332         // Read current frame into buffer (needed for the std-deviation tool)
333         read_frame(frame,
334                         0,
335                         start_position,
336                         frame_rate,
337                         0);
338
339
340 // Transfer accumulation to output with division if average is desired.
341         transfer_accum(frame);
342
343 //printf("SelTempAvgMain::process_buffer 2\n");
344
345
346         return 0;
347 }
348
349
350
351
352
353
354
355
356
357
358 // Reset accumulation
359 #define CLEAR_ACCUM(type, components, chroma) \
360 { \
361         float *row = (float*)accumulation; \
362         float *row_sq = (float*)accumulation_sq; \
363         if(chroma) \
364         { \
365                 for(int i = 0; i < w * h; i++) \
366                 { \
367                         *row++ = 0x0; \
368                         *row++ = 0x0; \
369                         *row++ = 0x0; \
370                         if(components == 4) *row++ = 0x0; \
371                         *row_sq++ = 0x0; \
372                         *row_sq++ = 0x0; \
373                         *row_sq++ = 0x0; \
374                 } \
375         } \
376         else \
377         { \
378                 bzero(row, w * h * sizeof(type) * components); \
379                 bzero(row_sq, w * h * 3 * sizeof(float)); \
380         } \
381 }
382
383
384 void SelTempAvgMain::clear_accum(int w, int h, int color_model)
385 {
386         switch(color_model)
387         {
388                 case BC_RGB888:
389                         CLEAR_ACCUM(int, 3, 0x0)
390                         break;
391                 case BC_RGB_FLOAT:
392                         CLEAR_ACCUM(float, 3, 0x0)
393                         break;
394                 case BC_RGBA8888:
395                         CLEAR_ACCUM(int, 4, 0x0)
396                         break;
397                 case BC_RGBA_FLOAT:
398                         CLEAR_ACCUM(float, 4, 0x0)
399                         break;
400                 case BC_YUV888:
401                         CLEAR_ACCUM(int, 3, 0x80)
402                         break;
403                 case BC_YUVA8888:
404                         CLEAR_ACCUM(int, 4, 0x80)
405                         break;
406                 case BC_YUV161616:
407                         CLEAR_ACCUM(int, 3, 0x8000)
408                         break;
409                 case BC_YUVA16161616:
410                         CLEAR_ACCUM(int, 4, 0x8000)
411                         break;
412         }
413 }
414 #define C2_IS(frame_row,chroma,max)  (float)(frame_row)/max
415
416
417 #define SUBTRACT_ACCUM(type, \
418         components, \
419         chroma, \
420         max) \
421 { \
422         if(1) \
423         { \
424                 for(int i = 0; i < h; i++) \
425                 { \
426                         float *accum_row = (float*)accumulation + \
427                                 i * w * components; \
428                         float *accum_row_sq = (float*)accumulation_sq + \
429                                 i * w *3; \
430                         type *frame_row = (type*)frame->get_rows()[i]; \
431                         float c1, c2, c3; \
432                         for(int j = 0; j < w; j++) \
433                         { \
434                                 c1 = ( (float)*frame_row )/max; \
435                                 frame_row++; \
436                                 c2 = ( (float)*frame_row )/max; \
437                                 frame_row++; \
438                                 c3 = ( (float)(*frame_row -0) )/max; \
439                                 frame_row++; \
440 \
441                                 *accum_row -= c1; \
442                                 accum_row++; \
443                                 *accum_row -= c2; \
444                                 accum_row++; \
445                                 *accum_row -= c3; \
446                                 accum_row++; \
447                                 if(components == 4) { *accum_row -= ((float)*frame_row++)/max; accum_row++; } \
448 \
449                                 *accum_row_sq++ -= c1*c1; \
450                                 *accum_row_sq++ -= c2*c2; \
451                                 *accum_row_sq++ -= c3*c3; \
452                         } \
453                 } \
454         } \
455 }
456
457
458 void SelTempAvgMain::subtract_accum(VFrame *frame)
459 {
460 // Just accumulate
461         if(config.nosubtract) return;
462         int w = frame->get_w();
463         int h = frame->get_h();
464
465         switch(frame->get_color_model())
466         {
467                 case BC_RGB888:
468                         SUBTRACT_ACCUM(unsigned char, 3, 0x0, 0xff)
469                         break;
470                 case BC_RGB_FLOAT:
471                         SUBTRACT_ACCUM(float, 3, 0x0, 1.0)
472                         break;
473                 case BC_RGBA8888:
474                         SUBTRACT_ACCUM(unsigned char, 4, 0x0, 0xff)
475                         break;
476                 case BC_RGBA_FLOAT:
477                         SUBTRACT_ACCUM(float, 4, 0x0, 1.0)
478                         break;
479                 case BC_YUV888:
480                         SUBTRACT_ACCUM(unsigned char, 3, 0x80, 0xff)
481                         break;
482                 case BC_YUVA8888:
483                         SUBTRACT_ACCUM(unsigned char, 4, 0x80, 0xff)
484                         break;
485                 case BC_YUV161616:
486                         SUBTRACT_ACCUM(uint16_t, 3, 0x8000, 0xffff)
487                         break;
488                 case BC_YUVA16161616:
489                         SUBTRACT_ACCUM(uint16_t, 4, 0x8000, 0xffff)
490                         break;
491         }
492 }
493
494
495 // The behavior has to be very specific to the color model because we rely on
496 // the value of full black to determine what pixel to show.
497 #define ADD_ACCUM(type, components, chroma, max) \
498 { \
499         float c1, c2, c3; \
500         if(1) \
501         { \
502                 for(int i = 0; i < h; i++) \
503                 { \
504                         float *accum_row = (float*)accumulation + \
505                                 i * w * components; \
506                         float *accum_row_sq = (float*)accumulation_sq + \
507                                 i * w *3; \
508                         type *frame_row = (type*)frame->get_rows()[i]; \
509                         for(int j = 0; j < w; j++) \
510                         { \
511                                 c1 = ( (float)*frame_row )/max; \
512                                 frame_row++; \
513                                 c2 = ( (float)*frame_row )/max; \
514                                 frame_row++; \
515                                 c3 = ( (float)*frame_row )/max; \
516                                 frame_row++; \
517 \
518                                 *accum_row += c1; \
519                                 accum_row++; \
520                                 *accum_row += c2; \
521                                 accum_row++; \
522                                 *accum_row += c3; \
523                                 accum_row++; \
524                                 if(components == 4) { *accum_row += ((float)*frame_row++)/max; accum_row++; } \
525 \
526                                 *accum_row_sq++ += c1*c1; \
527                                 *accum_row_sq++ += c2*c2; \
528                                 *accum_row_sq++ += c3*c3; \
529                         } \
530                 } \
531         } \
532 }
533
534
535 void SelTempAvgMain::add_accum(VFrame *frame)
536 {
537         int w = frame->get_w();
538         int h = frame->get_h();
539
540         switch(frame->get_color_model())
541         {
542                 case BC_RGB888:
543                         ADD_ACCUM(unsigned char, 3, 0x0, 0xff)
544                         break;
545                 case BC_RGB_FLOAT:
546                         ADD_ACCUM(float, 3, 0x0, 1.0)
547                         break;
548                 case BC_RGBA8888:
549                         ADD_ACCUM(unsigned char, 4, 0x0, 0xff)
550                         break;
551                 case BC_RGBA_FLOAT:
552                         ADD_ACCUM(float, 4, 0x0, 1.0)
553                         break;
554                 case BC_YUV888:
555                         ADD_ACCUM(unsigned char, 3, 0x80, 0xff)
556                         break;
557                 case BC_YUVA8888:
558                         ADD_ACCUM(unsigned char, 4, 0x80, 0xff)
559                         break;
560                 case BC_YUV161616:
561                         ADD_ACCUM(uint16_t, 3, 0x8000, 0xffff)
562                         break;
563                 case BC_YUVA16161616:
564                         ADD_ACCUM(uint16_t, 4, 0x8000, 0xffff)
565                         break;
566         }
567 }
568
569 #define MASKER(type, avg_thresh, std_thresh, c_now, c_mean, c_stddev, mask, gain, frame_rowp, max) \
570 { \
571       if ( (avg_thresh > fabs(c_now - c_mean)) &&  (std_thresh > c_stddev) ) \
572              if (mask) \
573                    frame_rowp = max; \
574              else \
575                    frame_rowp = (type)(c_mean*max*gain); \
576       else \
577              if (mask) \
578                    frame_rowp = 0; \
579              else \
580                    frame_rowp = (type)(c_now*max*gain); \
581 }
582
583 #define TRANSFER_ACCUM(type, components, chroma, max, c1_gain, c2_gain, c3_gain) \
584 { \
585         if(config.method == SelTempAvgConfig::METHOD_SELTEMPAVG) \
586         { \
587                 float denominator = config.frames; \
588                 float c1_now, c2_now, c3_now; \
589                 float c1_mean, c2_mean, c3_mean; \
590                 float c1_stddev, c2_stddev, c3_stddev; \
591                 for(int i = 0; i < h; i++) \
592                 { \
593                         float *accum_row = (float*)accumulation + i * w * components; \
594                         float *accum_row_sq = (float*)accumulation_sq + i * w * 3; \
595 \
596                         type *frame_row = (type*)frame->get_rows()[i]; \
597                         for(int j = 0; j < w; j++) \
598                         { \
599                                 c1_now = (float)(*frame_row)/max; \
600                                 frame_row++; \
601                                 c2_now = (float)(*frame_row)/max; \
602                                 frame_row++; \
603                                 c3_now = (float)(*frame_row)/max; \
604                                 frame_row -= 2; \
605 \
606                                 c1_mean = *accum_row/denominator; \
607                                 accum_row++; \
608                                 c2_mean = *accum_row/denominator; \
609                                 accum_row++; \
610                                 c3_mean = *accum_row/denominator; \
611                                 accum_row++; \
612                                 if(components == 4) { accum_row++; } \
613 \
614                                 c1_stddev = (*accum_row_sq++)/denominator - c1_mean*c1_mean; \
615                                 c2_stddev = (*accum_row_sq++)/denominator - c2_mean*c2_mean; \
616                                 c3_stddev = (*accum_row_sq++)/denominator - c3_mean*c3_mean; \
617 \
618                                 MASKER(type,  \
619                                        config.avg_threshold_RY, \
620                                        config.std_threshold_RY, \
621                                        c1_now, c1_mean, c1_stddev, config.mask_RY, c1_gain,\
622                                        *frame_row++, max)\
623                                 MASKER(type,  \
624                                        config.avg_threshold_GU, \
625                                        config.std_threshold_GU, \
626                                        c2_now, c2_mean, c2_stddev, config.mask_GU, c2_gain,\
627                                        *frame_row++, max)\
628                                 MASKER(type,  \
629                                        config.avg_threshold_BV, \
630                                        config.std_threshold_BV, \
631                                        c3_now, c3_mean, c3_stddev, config.mask_BV, c3_gain,\
632                                        *frame_row++, max)\
633                                 if(components == 4)  *frame_row++ = max; \
634                         } \
635                 } \
636         } \
637         else \
638         if(config.method == SelTempAvgConfig::METHOD_AVERAGE) \
639         { \
640                 float denominator = config.frames; \
641                 for(int i = 0; i < h; i++) \
642                 { \
643                         float *accum_row = (float*)accumulation + i * w * components; \
644                         type *frame_row = (type*)frame->get_rows()[i]; \
645                         for(int j = 0; j < w; j++) \
646                         { \
647 \
648                                 *frame_row++ = (type)( (*accum_row++ / denominator)*c1_gain*max ); \
649                                 *frame_row++ = (type)( (*accum_row++ / denominator)*c2_gain*max ); \
650                                 *frame_row++ = (type)( (*accum_row++ / denominator)*c3_gain*max ); \
651                                 if(components == 4) *frame_row++ = (type)((*accum_row++/denominator)*max ); \
652                         } \
653                 } \
654         } \
655         else \
656         if(config.method == SelTempAvgConfig::METHOD_STDDEV) \
657         { \
658                 float c1_mean, c2_mean, c3_mean; \
659                 float c1_stddev, c2_stddev, c3_stddev; \
660                 float denominator = config.frames; \
661                 for(int i = 0; i < h; i++) \
662                 { \
663                         float *accum_row = (float*)accumulation + i * w * components; \
664                         float *accum_row_sq = (float*)accumulation_sq + i * w * 3; \
665                         type *frame_row = (type*)frame->get_rows()[i]; \
666                         for(int j = 0; j < w; j++) \
667                         { \
668 \
669                                 c1_mean = *accum_row/denominator; \
670                                 accum_row++; \
671                                 c2_mean = *accum_row/denominator; \
672                                 accum_row++; \
673                                 c3_mean = *accum_row/denominator; \
674                                 accum_row++; \
675                                 if(components == 4) { accum_row++; } \
676 \
677                                 c1_stddev = (*accum_row_sq++)/denominator - c1_mean*c1_mean; \
678                                 c2_stddev = (*accum_row_sq++)/denominator - c2_mean*c2_mean; \
679                                 c3_stddev = (*accum_row_sq++)/denominator - c3_mean*c3_mean; \
680 \
681                                 *frame_row++ = (type)( c1_stddev*c1_gain*max ); \
682                                 *frame_row++ = (type)( c2_stddev*c2_gain*max ); \
683                                 *frame_row++ = (type)( c3_stddev*c3_gain*max ); \
684                                 if(components == 4) *frame_row++ = max; \
685                         } \
686                 } \
687         } \
688 }
689
690
691 void SelTempAvgMain::transfer_accum(VFrame *frame)
692 {
693         int w = frame->get_w();
694         int h = frame->get_h();
695
696         switch(frame->get_color_model())
697         {
698                 case BC_RGB888:
699                         TRANSFER_ACCUM(unsigned char, 3  , 0x0   , 0xff  , config.gain, config.gain, config.gain)
700                         break;
701                 case BC_RGB_FLOAT:
702                         TRANSFER_ACCUM(float        , 3  , 0x0   , 1     , config.gain, config.gain, config.gain)
703                         break;
704                 case BC_RGBA8888:
705                         TRANSFER_ACCUM(unsigned char, 4  , 0x0   , 0xff  , config.gain, config.gain, config.gain)
706                         break;
707                 case BC_RGBA_FLOAT:
708                         TRANSFER_ACCUM(float        , 4  , 0x0   , 1     , config.gain, config.gain, config.gain)
709                         break;
710                 case BC_YUV888:
711                         TRANSFER_ACCUM(unsigned char, 3  , 0x80  , 0xff  , config.gain, 1.0        , 1.0)
712                         break;
713                 case BC_YUVA8888:
714                         TRANSFER_ACCUM(unsigned char, 4  , 0x80  , 0xff  , config.gain, 1.0        , 1.0)
715                         break;
716                 case BC_YUV161616:
717                         TRANSFER_ACCUM(uint16_t     , 3  , 0x8000, 0xffff, config.gain, 1.0        , 1.0)
718                         break;
719                 case BC_YUVA16161616:
720                         TRANSFER_ACCUM(uint16_t     , 4  , 0x8000, 0xffff, config.gain, 1.0        , 1.0)
721                         break;
722         }
723 }
724
725
726
727 int SelTempAvgMain::load_configuration()
728 {
729         KeyFrame *prev_keyframe;
730         KeyFrame *temp_keyframe;
731
732         SelTempAvgConfig old_config;
733         old_config.copy_from(&config);
734
735         int64_t curpos = get_source_position();
736         prev_keyframe = get_prev_keyframe(curpos);
737         read_data(prev_keyframe);
738
739         if (curpos == prev_keyframe->position)
740                 onakeyframe = 1;
741         else
742                 onakeyframe = 0;
743
744         int64_t next_restart_keyframe     = curpos + config.frames;
745         int64_t prev_restart_keyframe     = curpos - config.frames;
746
747         for (int i = curpos; i < curpos + config.frames; i++)
748         {
749                 temp_keyframe = get_next_keyframe(i);
750                 if (
751                         (temp_keyframe->position < curpos + config.frames/2) &&
752                         (temp_keyframe->position > curpos) &&
753                         nextkeyframeisoffsetrestart(temp_keyframe)
754                         )
755                 {
756                         next_restart_keyframe = temp_keyframe->position;
757                         i = curpos + config.frames;
758                 } else if (temp_keyframe->position > i)
759                         i = temp_keyframe->position;
760         }
761
762         for (int i = curpos; i > curpos - config.frames; i--)
763         {
764                 temp_keyframe = get_prev_keyframe(i);
765                 if (
766                         (temp_keyframe->position > curpos - config.frames/2) &&
767                         (temp_keyframe->position < curpos) &&
768                         nextkeyframeisoffsetrestart(temp_keyframe)
769                         )
770                 {
771                         prev_restart_keyframe = temp_keyframe->position;
772                         i = curpos - config.frames;
773                 } else if (temp_keyframe->position < i)
774                         i = temp_keyframe->position;
775         }
776
777         restartoffset = -config.frames/2;
778
779         if (onakeyframe && config.offset_restartmarker_keyframe)
780                 restartoffset = 0;
781         else if ((curpos - prev_restart_keyframe) < config.frames/2)
782                 restartoffset = prev_restart_keyframe - curpos;
783         else if ((next_restart_keyframe - curpos) < config.frames/2) {
784                 restartoffset = (next_restart_keyframe - curpos) - config.frames;
785                 // Probably should put another if in here, (when two "restart" keyframes are close together
786         }
787
788         return !old_config.equivalent(&config);
789 }
790
791 void SelTempAvgMain::save_data(KeyFrame *keyframe)
792 {
793         FileXML output;
794
795 // cause data to be stored directly in text
796         output.set_shared_output(keyframe->xbuf);
797         output.tag.set_title("SELECTIVE_TEMPORAL_AVERAGE");
798         output.tag.set_property("FRAMES", config.frames);
799         output.tag.set_property("METHOD", config.method);
800         output.tag.set_property("OFFSETMODE", config.offsetmode);
801         output.tag.set_property("PARANOID", config.paranoid);
802         output.tag.set_property("NOSUBTRACT", config.nosubtract);
803         output.tag.set_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe);
804         output.tag.set_property("OFFSETMODE_FIXED_VALUE", config.offset_fixed_value);
805         output.tag.set_property("GAIN", config.gain);
806
807
808         output.tag.set_property("AVG_THRESHOLD_RY", config.avg_threshold_RY);
809         output.tag.set_property("AVG_THRESHOLD_GU", config.avg_threshold_GU);
810         output.tag.set_property("AVG_THRESHOLD_BV", config.avg_threshold_BV);
811         output.tag.set_property("STD_THRESHOLD_RY", config.std_threshold_RY);
812         output.tag.set_property("STD_THRESHOLD_GU", config.std_threshold_GU);
813         output.tag.set_property("STD_THRESHOLD_BV", config.std_threshold_BV);
814
815         output.tag.set_property("MASK_RY", config.mask_RY);
816         output.tag.set_property("MASK_GU", config.mask_GU);
817         output.tag.set_property("MASK_BV", config.mask_BV);
818
819         output.append_tag();
820         output.tag.set_title("/SELECTIVE_TEMPORAL_AVERAGE");
821         output.append_tag();
822         output.append_newline();
823         output.terminate_string();
824 }
825
826 void SelTempAvgMain::read_data(KeyFrame *keyframe)
827 {
828         FileXML input;
829
830         input.set_shared_input(keyframe->xbuf);
831
832         while(!input.read_tag())
833         {
834                 if(input.tag.title_is("SELECTIVE_TEMPORAL_AVERAGE"))
835                 {
836                         config.frames = input.tag.get_property("FRAMES", config.frames);
837                         config.method = input.tag.get_property("METHOD", config.method);
838                         config.offsetmode = input.tag.get_property("OFFSETMODE", config.offsetmode);
839                         config.paranoid = input.tag.get_property("PARANOID", config.paranoid);
840                         config.nosubtract = input.tag.get_property("NOSUBTRACT", config.nosubtract);
841                         config.offset_restartmarker_keyframe = input.tag.get_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe);
842                         config.offset_fixed_value = input.tag.get_property("OFFSETMODE_FIXED_VALUE", config.offset_fixed_value);
843                         config.gain = input.tag.get_property("gain", config.gain);
844
845                         config.avg_threshold_RY = input.tag.get_property("AVG_THRESHOLD_RY", config.avg_threshold_RY);
846                         config.avg_threshold_GU = input.tag.get_property("AVG_THRESHOLD_GU", config.avg_threshold_GU);
847                         config.avg_threshold_BV = input.tag.get_property("AVG_THRESHOLD_BV", config.avg_threshold_BV);
848                         config.std_threshold_RY = input.tag.get_property("STD_THRESHOLD_RY", config.std_threshold_RY);
849                         config.std_threshold_GU = input.tag.get_property("STD_THRESHOLD_GU", config.std_threshold_GU);
850                         config.std_threshold_BV = input.tag.get_property("STD_THRESHOLD_BV", config.std_threshold_BV);
851
852                         config.mask_RY = input.tag.get_property("MASK_RY", config.mask_RY);
853                         config.mask_GU = input.tag.get_property("MASK_GU", config.mask_GU);
854                         config.mask_BV = input.tag.get_property("MASK_BV", config.mask_BV);
855
856                 }
857         }
858 }
859
860
861
862 int SelTempAvgMain::nextkeyframeisoffsetrestart(KeyFrame *keyframe)
863 {
864         FileXML input;
865
866         input.set_shared_input(keyframe->xbuf);
867
868         while(!input.read_tag())
869         {
870                 if(input.tag.title_is("SELECTIVE_TEMPORAL_AVERAGE"))
871                 {
872                         return(input.tag.get_property("OFFSETMODE_RESTARTMODE_KEYFRAME", config.offset_restartmarker_keyframe));
873                 }
874         }
875         return (0);
876 }
877
878
879
880 void SelTempAvgMain::update_gui()
881 {
882         if(thread)
883         {
884                 ((SelTempAvgWindow*)thread->window)->lock_window("SelTempAvgMain::update_gui");
885                 if(load_configuration())
886                 {
887                         ((SelTempAvgWindow*)thread->window)->total_frames->update(config.frames);
888
889                         ((SelTempAvgWindow*)thread->window)->method_none->update(         config.method == SelTempAvgConfig::METHOD_NONE);
890                         ((SelTempAvgWindow*)thread->window)->method_seltempavg->update(   config.method == SelTempAvgConfig::METHOD_SELTEMPAVG);
891                         ((SelTempAvgWindow*)thread->window)->method_average->update(      config.method == SelTempAvgConfig::METHOD_AVERAGE);
892                         ((SelTempAvgWindow*)thread->window)->method_stddev->update(       config.method == SelTempAvgConfig::METHOD_STDDEV);
893
894                         ((SelTempAvgWindow*)thread->window)->offset_fixed->update(        config.offsetmode == SelTempAvgConfig::OFFSETMODE_FIXED);
895                         ((SelTempAvgWindow*)thread->window)->offset_restartmarker->update(config.offsetmode == SelTempAvgConfig::OFFSETMODE_RESTARTMARKERSYS);
896
897
898                         ((SelTempAvgWindow*)thread->window)->paranoid->update(config.paranoid);
899                         ((SelTempAvgWindow*)thread->window)->no_subtract->update(config.nosubtract);
900
901                         ((SelTempAvgWindow*)thread->window)->offset_fixed_value->update((int64_t)config.offset_fixed_value);
902                         ((SelTempAvgWindow*)thread->window)->gain->update(config.gain);
903
904                         ((SelTempAvgWindow*)thread->window)->avg_threshold_RY->update((float)config.avg_threshold_RY);
905                         ((SelTempAvgWindow*)thread->window)->avg_threshold_GU->update((float)config.avg_threshold_GU);
906                         ((SelTempAvgWindow*)thread->window)->avg_threshold_BV->update((float)config.avg_threshold_BV);
907                         ((SelTempAvgWindow*)thread->window)->std_threshold_RY->update((float)config.std_threshold_RY);
908                         ((SelTempAvgWindow*)thread->window)->std_threshold_GU->update((float)config.std_threshold_GU);
909                         ((SelTempAvgWindow*)thread->window)->std_threshold_BV->update((float)config.std_threshold_BV);
910
911                         ((SelTempAvgWindow*)thread->window)->mask_RY->update(config.mask_RY);
912                         ((SelTempAvgWindow*)thread->window)->mask_GU->update(config.mask_GU);
913                         ((SelTempAvgWindow*)thread->window)->mask_BV->update(config.mask_BV);
914                 }
915                 ((SelTempAvgWindow*)thread->window)->offset_restartmarker_pos->update((int64_t)restartoffset);
916                 ((SelTempAvgWindow*)thread->window)->offset_restartmarker_keyframe->update((config.offset_restartmarker_keyframe) && (onakeyframe));
917                 ((SelTempAvgWindow*)thread->window)->unlock_window();
918         }
919 }
920
921
922
923
924
925
926
927
928
929