]> git.sesse.net Git - vlc/blob - modules/video_filter/atmo/AtmoOutputFilter.cpp
threads: Make sure we don't re-create a thread if the object has already one.
[vlc] / modules / video_filter / atmo / AtmoOutputFilter.cpp
1 /*
2  * AtmoOutputFilter.cpp: Post Processor for the color data retrieved from
3  * a CAtmoInput
4  *
5  * mostly 1:1 from vdr-linux-src "filter.c" copied
6  *
7  * See the README.txt file for copyright information and how to reach the author(s).
8  *
9  * $Id$
10  */
11
12 #include <string.h>
13 #include "AtmoOutputFilter.h"
14
15
16
17 CAtmoOutputFilter::CAtmoOutputFilter(CAtmoConfig *atmoConfig)
18 {
19    this->m_pAtmoConfig = atmoConfig;
20    ResetFilter();
21 }
22
23 CAtmoOutputFilter::~CAtmoOutputFilter(void)
24 {
25 }
26
27 void CAtmoOutputFilter::ResetFilter(void)
28 {
29   // reset filter values
30   MeanFilter(true);
31   PercentFilter(true);
32 }
33
34 tColorPacket CAtmoOutputFilter::Filtering(tColorPacket ColorPacket)
35 {
36   filter_input = ColorPacket;
37
38   switch (m_pAtmoConfig->getLiveViewFilterMode())
39   {
40     case afmNoFilter:
41          filter_output = filter_input;
42     break;
43
44     case afmCombined:
45          MeanFilter(false);
46     break;
47
48     case afmPercent:
49          PercentFilter(false);
50     break;
51
52     default:
53          filter_output = filter_input;
54     break;
55   }
56
57   return filter_output;
58 }
59
60 void CAtmoOutputFilter::PercentFilter(ATMO_BOOL init)
61 {
62   // last values needed for the percentage filter
63   static tColorPacket filter_output_old;
64
65   if (init) // Initialization
66   {
67     memset(&filter_output_old, 0, sizeof(filter_output_old));
68     return;
69   }
70
71   int percentNew = this->m_pAtmoConfig->getLiveViewFilter_PercentNew();
72
73   for (int ch = 0; ch < ATMO_NUM_CHANNELS; ch++)
74   {
75         filter_output.channel[ch].r = (filter_input.channel[ch].r *
76          (100-percentNew) + filter_output_old.channel[ch].r * percentNew) / 100;
77         
78     filter_output.channel[ch].g = (filter_input.channel[ch].g *
79          (100-percentNew) + filter_output_old.channel[ch].g * percentNew) / 100;
80
81         filter_output.channel[ch].b = (filter_input.channel[ch].b *
82          (100-percentNew) + filter_output_old.channel[ch].b * percentNew) / 100;
83   }
84
85   filter_output_old = filter_output;
86 }
87
88 void CAtmoOutputFilter::MeanFilter(ATMO_BOOL init)
89 {
90   // needed vor the running mean value filter
91   static tColorPacketLongInt mean_sums;
92   static tColorPacket mean_values;
93   // needed for the percentage filter
94   static tColorPacket filter_output_old;
95   static int filter_length_old;
96   char reinitialize = 0;
97   long int tmp;
98
99   if (init) // Initialization
100   {
101     memset(&filter_output_old, 0, sizeof(filter_output_old));
102     memset(&mean_sums, 0, sizeof(mean_sums));
103     memset(&mean_values, 0, sizeof(mean_values));
104     return;
105   }
106   int AtmoSetup_Filter_MeanLength = m_pAtmoConfig->getLiveViewFilter_MeanLength();
107   int AtmoSetup_Filter_PercentNew = m_pAtmoConfig->getLiveViewFilter_PercentNew();
108   int AtmoSetup_Filter_MeanThreshold = m_pAtmoConfig->getLiveViewFilter_MeanThreshold();
109
110   // if filter_length has changed
111   if (filter_length_old != AtmoSetup_Filter_MeanLength)
112   {
113     // force reinitialization of the filter
114     reinitialize = 1;
115   }
116   filter_length_old = AtmoSetup_Filter_MeanLength;
117
118   if (filter_length_old < 20) filter_length_old = 20; // avoid division by 0
119
120   for (int ch = 0; ch < ATMO_NUM_CHANNELS; ch++)
121   {
122     // calculate the mean-value filters
123     mean_sums.channel[ch].r +=
124          (long int)(filter_input.channel[ch].r - mean_values.channel[ch].r); // red
125     tmp = mean_sums.channel[ch].r / ((long int)filter_length_old / 20);
126     if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
127     mean_values.channel[ch].r = (unsigned char)tmp;
128
129     mean_sums.channel[ch].g +=
130         (long int)(filter_input.channel[ch].g - mean_values.channel[ch].g); // green
131     tmp = mean_sums.channel[ch].g / ((long int)filter_length_old / 20);
132     if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
133     mean_values.channel[ch].g = (unsigned char)tmp;
134
135     mean_sums.channel[ch].b +=
136         (long int)(filter_input.channel[ch].b - mean_values.channel[ch].b); // blue
137     tmp = mean_sums.channel[ch].b / ((long int)filter_length_old / 20);
138     if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
139     mean_values.channel[ch].b = (unsigned char)tmp;
140
141     // check, if there is a jump -> check if differences between actual values and filter values are too big
142
143     long int dist; // distance between the two colors in the 3D RGB space
144     dist = (mean_values.channel[ch].r - filter_input.channel[ch].r) *
145            (mean_values.channel[ch].r - filter_input.channel[ch].r) +
146            (mean_values.channel[ch].g - filter_input.channel[ch].g) *
147            (mean_values.channel[ch].g - filter_input.channel[ch].g) +
148            (mean_values.channel[ch].b - filter_input.channel[ch].b) *
149            (mean_values.channel[ch].b - filter_input.channel[ch].b);
150
151     /*
152        if (dist > 0) { dist = (long int)sqrt((double)dist); }
153        avoid sqrt(0) (TODO: necessary?)
154        I think its cheaper to calculate the square of something ..? insteas geting the square root?
155     */
156     double distMean = ((double)AtmoSetup_Filter_MeanThreshold * 3.6f);
157     distMean = distMean * distMean;
158
159     /*
160       compare calculated distance with the filter threshold
161           if ((dist > (long int)((double)AtmoSetup.Filter_MeanThreshold * 3.6f)) || ( reinitialize == 1))
162    */
163
164         if ((dist > distMean) || ( reinitialize == 1))
165     {
166       // filter jump detected -> set the long filters to the result of the short filters
167       filter_output.channel[ch] = mean_values.channel[ch] = filter_input.channel[ch];
168
169       mean_sums.channel[ch].r = filter_input.channel[ch].r *
170                                 (filter_length_old / 20);
171       mean_sums.channel[ch].g = filter_input.channel[ch].g *
172                                 (filter_length_old / 20);
173       mean_sums.channel[ch].b = filter_input.channel[ch].b *
174                                 (filter_length_old / 20);
175     }
176     else
177     {
178       // apply an additional percent filter and return calculated values
179
180           filter_output.channel[ch].r = (mean_values.channel[ch].r *
181           (100-AtmoSetup_Filter_PercentNew) +
182           filter_output_old.channel[ch].r * AtmoSetup_Filter_PercentNew) / 100;
183
184           filter_output.channel[ch].g = (mean_values.channel[ch].g *
185           (100-AtmoSetup_Filter_PercentNew) +
186           filter_output_old.channel[ch].g * AtmoSetup_Filter_PercentNew) / 100;
187
188           filter_output.channel[ch].b = (mean_values.channel[ch].b *
189           (100-AtmoSetup_Filter_PercentNew) +
190           filter_output_old.channel[ch].b * AtmoSetup_Filter_PercentNew) / 100;
191     }
192   }
193   filter_output_old = filter_output;
194 }