no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / overlaysample.C
1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published
4  * by the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful, but
8  * WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  * General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public
13  * License along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
15  * USA
16  */
17
18 #include "overlayframe.h"
19 #include "overlaysample.h"
20
21 /* Fully resampled scale / translate / blend ******************************/
22 /* resample into a temporary row vector, then blend */
23
24 SamplePackage::SamplePackage()
25 {
26 }
27
28 SampleUnit::SampleUnit(SampleEngine *server)
29  : LoadClient(server)
30 {
31         this->engine = server;
32 }
33
34 SampleUnit::~SampleUnit()
35 {
36 }
37
38 void SampleUnit::process_package(LoadPackage *package)
39 {
40         pkg = (SamplePackage*)package;
41
42         float i1  = engine->in1;
43         float i2  = engine->in2;
44         float o1  = engine->out1;
45         float o2  = engine->out2;
46
47         if(i2 - i1 <= 0 || o2 - o1 <= 0)
48                 return;
49
50         voutput = engine->output;
51         vinput = engine->input;
52         mode = engine->mode;
53         fade = BC_CModels::has_alpha(vinput->get_color_model()) &&
54                 mode == TRANSFER_REPLACE ? 1.f : engine->alpha;
55
56         //iw  = vinput->get_w();
57         i1i = floor(i1);
58         i2i = ceil(i2);
59         i1f = 1.f - i1 + i1i;
60         i2f = 1.f - i2i + i2;
61
62         o1i = floor(o1);
63         o2i = ceil(o2);
64         o1f = 1.f - o1 + o1i;
65         o2f = 1.f - o2i + o2;
66         oh  = o2i - o1i;
67
68         k  = engine->kernel->lookup;
69         //kw  = engine->kernel->width;
70         //kn  = engine->kernel->n;
71         kd = engine->kd;
72
73         lookup_sx0 = engine->lookup_sx0;
74         lookup_sx1 = engine->lookup_sx1;
75         lookup_sk = engine->lookup_sk;
76         lookup_wacc = engine->lookup_wacc;
77
78         switch( vinput->get_color_model() ) {
79         case BC_RGB_FLOAT:      rgb_float();    break;
80         case BC_RGBA_FLOAT:     rgba_float();   break;
81         case BC_RGB888:         rgb888();       break;
82         case BC_YUV888:         yuv888();       break;
83         case BC_RGBA8888:       rgba8888();     break;
84         case BC_YUVA8888:       yuva8888();     break;
85         case BC_RGB161616:      rgb161616();    break;
86         case BC_YUV161616:      yuv161616();    break;
87         case BC_RGBA16161616:   rgba16161616(); break;
88         case BC_YUVA16161616:   yuva16161616();  break;
89         }
90 }
91
92
93 SampleEngine::SampleEngine(int cpus)
94  : LoadServer(cpus, cpus)
95 {
96         lookup_sx0 = 0;
97         lookup_sx1 = 0;
98         lookup_sk = 0;
99         lookup_wacc = 0;
100         kd = 0;
101 }
102
103 SampleEngine::~SampleEngine()
104 {
105         if(lookup_sx0) delete [] lookup_sx0;
106         if(lookup_sx1) delete [] lookup_sx1;
107         if(lookup_sk) delete [] lookup_sk;
108         if(lookup_wacc) delete [] lookup_wacc;
109 }
110
111 /*
112  * unlike the Direct and NN engines, the Sample engine works across
113  * output columns (it makes for more economical memory addressing
114  * during convolution)
115  */
116 void SampleEngine::init_packages()
117 {
118         int   iw  = input->get_w();
119         int   i1i = floor(in1);
120         int   i2i = ceil(in2);
121         float i1f = 1.f - in1 + i1i;
122         float i2f = 1.f - i2i + in2;
123
124         int   oy  = floor(out1);
125         float oyf = out1 - oy;
126         int   oh  = ceil(out2) - oy;
127
128         float *k  = kernel->lookup;
129         float kw  = kernel->width;
130         int   kn  = kernel->n;
131
132         if(in2 - in1 <= 0 || out2 - out1 <= 0)
133                 return;
134
135         /* determine kernel spatial coverage */
136         float scale = (out2 - out1) / (in2 - in1);
137         float iscale = (in2 - in1) / (out2 - out1);
138         float coverage = fabs(1.f / scale);
139         float bound = (coverage < 1.f ? kw : kw * coverage) - (.5f / TRANSFORM_SPP);
140         float coeff = (coverage < 1.f ? 1.f : scale) * TRANSFORM_SPP;
141
142         delete [] lookup_sx0;
143         delete [] lookup_sx1;
144         delete [] lookup_sk;
145         delete [] lookup_wacc;
146
147         lookup_sx0 = new int[oh];
148         lookup_sx1 = new int[oh];
149         lookup_sk = new int[oh];
150         lookup_wacc = new float[oh];
151
152         kd = (double)coeff * (1 << INDEX_FRACTION) + .5;
153
154         /* precompute kernel values and weight sums */
155         for(int i = 0; i < oh; i++) {
156                 /* map destination back to source */
157                 double sx = (i - oyf + .5) * iscale + in1 - .5;
158
159                 /*
160                  * clip iteration to source area but not source plane. Points
161                  * outside the source plane count as transparent. Points outside
162                  * the source area don't count at all.  The actual convolution
163                  * later will be clipped to both, but we need to compute
164                  * weights.
165                  */
166                 int sx0 = mmax((int)floor(sx - bound) + 1, i1i);
167                 int sx1 = mmin((int)ceil(sx + bound), i2i);
168                 int ki = (double)(sx0 - sx) * coeff * (1 << INDEX_FRACTION)
169                                 + (1 << (INDEX_FRACTION - 1)) + .5;
170                 float wacc=0.;
171
172                 lookup_sx0[i] = -1;
173                 lookup_sx1[i] = -1;
174
175                 for(int j= sx0; j < sx1; j++) {
176                         int kv = (ki >> INDEX_FRACTION);
177                         if(kv > kn) break;
178                         if(kv >= -kn) {
179                                 /*
180                                  * the contribution of the first and last input pixel (if
181                                  * fractional) are linearly weighted by the fraction
182                                  */
183                                 float fk = k[abs(kv)];
184                                 wacc += j == i1i ? fk * i1f : j+1 == i2i ? fk * i2f : fk;
185
186                                 /* this is where we clip the kernel convolution to the source plane */
187                                 if(j >= 0 && j < iw) {
188                                         if(lookup_sx0[i] == -1) {
189                                                 lookup_sx0[i] = j;
190                                                 lookup_sk[i] = ki;
191                                         }
192                                         lookup_sx1[i] = j + 1;
193                                 }
194                         }
195                         ki += kd;
196                 }
197                 lookup_wacc[i] = wacc > 0. ? 1. / wacc : 0.;
198         }
199
200         int cols = col_out2 - col_out1;
201         int pkgs = get_total_packages();
202         int col1 = col_out1, col2 = col1;
203         for(int i = 0; i < pkgs; col1=col2 ) {
204                 SamplePackage *package = (SamplePackage*)get_package(i);
205                 col2 = ++i * cols / pkgs + col_out1;
206                 package->out_col1 = col1;
207                 package->out_col2 = col2;
208         }
209 }
210
211 LoadClient* SampleEngine::new_client()
212 {
213         return new SampleUnit(this);
214 }
215
216 LoadPackage* SampleEngine::new_package()
217 {
218         return new SamplePackage;
219 }
220
221