add histogram frame averaging, lock renderengine during updates, fix ffmpeg btn booby
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / scale / scale.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 "filexml.h"
24 #include "language.h"
25 #include "mwindow.h"
26 #include "pluginserver.h"
27 #include "scale.h"
28 #include "scalewin.h"
29
30 #include <string.h>
31
32
33 REGISTER_PLUGIN(ScaleMain)
34
35
36
37 ScaleConfig::ScaleConfig()
38 {
39         reset(RESET_DEFAULT_SETTINGS);
40 }
41
42 void ScaleConfig::reset(int clear)
43 {
44         switch(clear) {
45                 case RESET_X_FACTOR :
46                         x_factor = 1;
47                         break;
48                 case RESET_Y_FACTOR :
49                         y_factor = 1;
50                         break;
51                 case RESET_WIDTH :
52                         width = 1280;
53                         break;
54                 case RESET_HEIGHT :
55                         height = 720;
56                         break;
57                 case RESET_ALL :
58                 case RESET_DEFAULT_SETTINGS :
59                 default:
60                         type = FIXED_SCALE;
61                         x_factor = y_factor = 1;
62                         width = 1280; height = 720;
63                         constrain = 0;
64                         break;
65         }
66 }
67
68
69 void ScaleConfig::copy_from(ScaleConfig &src)
70 {
71         type = src.type;
72         x_factor = src.x_factor;
73         y_factor = src.y_factor;
74         constrain = src.constrain;
75         width = src.width;
76         height = src.height;
77 }
78 int ScaleConfig::equivalent(ScaleConfig &src)
79 {
80         return type != src.type ? 0 : type == FIXED_SCALE ?
81                 EQUIV(x_factor, src.x_factor) && EQUIV(y_factor, src.y_factor) &&
82                         constrain == src.constrain :
83                 width == src.width && height == src.height;
84 }
85
86 void ScaleConfig::interpolate(ScaleConfig &prev, ScaleConfig &next,
87         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
88 {
89         double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
90         double v = 1. - u;
91
92         this->type = prev.type;
93         this->x_factor = u*prev.x_factor + v*next.x_factor;
94         this->y_factor = u*prev.y_factor + v*next.y_factor;
95         this->constrain = prev.constrain;
96         this->width = u*prev.width + v*next.width;
97         this->height = u*prev.height + v*next.height;
98 }
99
100
101
102 ScaleMain::ScaleMain(PluginServer *server)
103  : PluginVClient(server)
104 {
105         this->server = server;
106         overlayer = 0;
107 }
108
109 ScaleMain::~ScaleMain()
110 {
111         if(overlayer) delete overlayer;
112 }
113
114 const char* ScaleMain::plugin_title() { return N_("Scale"); }
115 int ScaleMain::is_realtime() { return 1; }
116
117
118
119 LOAD_CONFIGURATION_MACRO(ScaleMain, ScaleConfig)
120
121
122 void ScaleMain::set_type(int type)
123 {
124         if( type != config.type ) {
125                 config.type = type;
126                 ScaleWin *swin = (ScaleWin *)thread->window;
127                 int fixed_scale = type == FIXED_SCALE ? 1 : 0;
128                 swin->use_scale->update(fixed_scale);
129                 swin->x_factor_text->enabled = fixed_scale;
130                 swin->y_factor_text->enabled = fixed_scale;
131                 int fixed_size = 1 - fixed_scale;
132                 swin->use_size->update(fixed_size);
133                 swin->width_text->enabled = fixed_size;
134                 swin->height_text->enabled = fixed_size;
135                 send_configure_change();
136         }
137 }
138
139 void ScaleMain::save_data(KeyFrame *keyframe)
140 {
141         FileXML output;
142
143 // cause data to be stored directly in text
144         output.set_shared_output(keyframe->xbuf);
145
146 // Store data
147         output.tag.set_title("SCALE");
148         output.tag.set_property("TYPE", config.type);
149         output.tag.set_property("X_FACTOR", config.x_factor);
150         output.tag.set_property("Y_FACTOR", config.y_factor);
151         output.tag.set_property("WIDTH", config.width);
152         output.tag.set_property("HEIGHT", config.height);
153         output.tag.set_property("CONSTRAIN", config.constrain);
154         output.append_tag();
155         output.tag.set_title("/SCALE");
156         output.append_tag();
157         output.append_newline();
158         output.terminate_string();
159 // data is now in *text
160 }
161
162 void ScaleMain::read_data(KeyFrame *keyframe)
163 {
164         FileXML input;
165
166         input.set_shared_input(keyframe->xbuf);
167
168         int result = 0;
169         config.constrain = 0;
170
171         while(!result)
172         {
173                 result = input.read_tag();
174
175                 if(!result)
176                 {
177                         if(input.tag.title_is("SCALE"))
178                         {
179                                 config.type = input.tag.get_property("TYPE", config.type);
180                                 config.x_factor = input.tag.get_property("X_FACTOR", config.x_factor);
181                                 config.y_factor = input.tag.get_property("Y_FACTOR", config.y_factor);
182                                 config.constrain = input.tag.get_property("CONSTRAIN", config.constrain);
183                                 config.width = input.tag.get_property("WIDTH", config.x_factor);
184                                 config.height = input.tag.get_property("HEIGHT", config.y_factor);
185                         }
186                 }
187         }
188 }
189
190
191
192
193
194
195
196
197 int ScaleMain::process_buffer(VFrame *frame,
198         int64_t start_position,
199         double frame_rate)
200 {
201         VFrame *input, *output;
202         input = output = frame;
203
204         load_configuration();
205         read_frame(frame, 0, start_position, frame_rate, get_use_opengl());
206
207 // No scaling
208         if( config.type == FIXED_SCALE ?
209                 config.x_factor == 1 && config.y_factor == 1 :
210                 config.width == frame->get_w() && config.height == frame->get_h() )
211                 return 0;
212
213         if(get_use_opengl()) return run_opengl();
214
215         VFrame *temp_frame = new_temp(frame->get_w(), frame->get_h(),
216                         frame->get_color_model());
217         temp_frame->copy_from(frame);
218         input = temp_frame;
219
220         if(!overlayer)
221         {
222                 overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
223         }
224
225
226 // Perform scaling
227         float in_x1, in_x2, in_y1, in_y2, out_x1, out_x2, out_y1, out_y2;
228         calculate_transfer(output,
229                 in_x1, in_x2, in_y1, in_y2,
230                 out_x1, out_x2, out_y1, out_y2);
231         output->clear_frame();
232
233 // printf("ScaleMain::process_realtime 3 output=%p input=%p config.x_factor=%f config.y_factor=%f"
234 //      " config.width=%d config.height=%d config.type=%d   %f %f %f %f -> %f %f %f %f\n",
235 //      output, input, config.x_factor, config.y_factor, config.width, config.height, config.type,
236 //      in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
237         overlayer->overlay(output, input,
238                 in_x1, in_y1, in_x2, in_y2,
239                 out_x1, out_y1, out_x2, out_y2,
240                 1, TRANSFER_REPLACE, get_interpolation_type());
241
242         return 0;
243 }
244
245 void ScaleMain::calculate_transfer(VFrame *frame,
246         float &in_x1, float &in_x2, float &in_y1, float &in_y2,
247         float &out_x1, float &out_x2, float &out_y1, float &out_y2)
248 {
249         float fw = (float)frame->get_w();
250         float fh = (float)frame->get_h();
251         in_x1 = in_y1 = 0;
252         in_x2 = fw;
253         in_y2 = fh;
254         float x_factor = config.type == FIXED_SCALE ? config.x_factor :
255                 in_x2 > 0. ? (float)config.width / in_x2 : 0;
256         float y_factor = config.type == FIXED_SCALE ? config.y_factor :
257                 in_y2 > 0. ? (float)config.height / in_y2 : 0;
258
259         float fw2 = fw/2, fw2s = fw2*x_factor;
260         float fh2 = fh/2, fh2s = fh2*y_factor;
261         out_x1 = fw2 - fw2s;
262         out_x2 = fw2 + fw2s;
263         out_y1 = fh2 - fh2s;
264         out_y2 = fh2 + fh2s;
265
266         if(out_x1 < 0) {
267                 in_x1 = x_factor>0 ? in_x1 - out_x1/x_factor : 0;
268                 out_x1 = 0;
269         }
270
271         if(out_x2 > frame->get_w()) {
272                 in_x2 = x_factor>0 ? in_x2 - (out_x2-frame->get_w())/x_factor : 0;
273                 out_x2 = frame->get_w();
274         }
275
276         if(out_y1 < 0) {
277                 in_y1 = y_factor>0 ? in_y1 - out_y1/y_factor : 0;
278                 out_y1 = 0;
279         }
280
281         if(out_y2 > frame->get_h()) {
282                 in_y2 = y_factor>0 ? in_y2 - (out_y2-frame->get_h())/y_factor : 0;
283                 out_y2 = frame->get_h();
284         }
285 }
286
287 int ScaleMain::handle_opengl()
288 {
289 #ifdef HAVE_GL
290         float in_x1, in_x2, in_y1, in_y2, out_x1, out_x2, out_y1, out_y2;
291         calculate_transfer(get_output(),
292                 in_x1, in_x2, in_y1, in_y2,
293                 out_x1, out_x2, out_y1, out_y2);
294
295         get_output()->to_texture();
296         get_output()->enable_opengl();
297         get_output()->init_screen();
298         get_output()->clear_pbuffer();
299         get_output()->bind_texture(0);
300         get_output()->draw_texture(
301                 in_x1, in_y1, in_x2, in_y2,
302                 out_x1, out_y1, out_x2, out_y2);
303         get_output()->set_opengl_state(VFrame::SCREEN);
304 #endif
305         return 0;
306 }
307
308
309
310 NEW_WINDOW_MACRO(ScaleMain, ScaleWin)
311
312 void ScaleMain::update_gui()
313 {
314         if(thread)
315         {
316                 load_configuration();
317                 thread->window->lock_window();
318                 set_type(config.type);
319                 ScaleWin *swin = (ScaleWin *)thread->window;
320                 swin->update(RESET_ALL);
321
322                 // Needed to update Enable-Disable GUI when "Preset Edit" is used.
323                 swin->update_scale_size_enable();
324
325                 thread->window->unlock_window();
326         }
327 }
328
329
330