add ffmpeg image2 formats, fix segv when quit with render menu active
[goodguy/history.git] / cinelerra-5.1 / cinelerra / commonrender.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 "auto.h"
23 #include "cache.h"
24 #include "commonrender.h"
25 #include "condition.h"
26 #include "edl.h"
27 #include "edlsession.h"
28 #include "intautos.h"
29 #include "localsession.h"
30 #include "mainsession.h"
31 #include "module.h"
32 #include "mwindow.h"
33 #include "patchbay.h"
34 #include "patch.h"
35 #include "playabletracks.h"
36 #include "preferences.h"
37 #include "renderengine.h"
38 #include "track.h"
39 #include "tracks.h"
40 #include "transportque.h"
41 #include "virtualconsole.h"
42
43 CommonRender::CommonRender(RenderEngine *renderengine)
44  : Thread(1, 0, 0)
45 {
46         this->renderengine = renderengine;
47         reset_parameters();
48         start_lock = new Condition(0, "CommonRender::start_lock");
49 }
50
51 CommonRender::~CommonRender()
52 {
53         delete_vconsole();
54         if(modules)
55         {
56                 for(int i = 0; i < total_modules; i++)
57                         delete modules[i];
58                 delete [] modules;
59         }
60         delete start_lock;
61 }
62
63 void CommonRender::reset_parameters()
64 {
65         total_modules = 0;
66         modules = 0;
67         vconsole = 0;
68         done = 0;
69         interrupt = 0;
70         asynchronous = 0;
71         restart_plugins = 0;
72 }
73
74 void CommonRender::arm_command()
75 {
76         int64_t temp_length = 1;
77
78         current_position = tounits(renderengine->command->playbackstart, 0);
79         if(renderengine->command->realtime) init_output_buffers();
80
81         if(test_reconfigure(current_position, temp_length))
82         {
83                 restart_playback();
84         }
85         else
86         {
87                 vconsole->start_playback();
88         }
89
90         done = 0;
91         interrupt = 0;
92         restart_plugins = 0;
93 }
94
95
96
97 void CommonRender::create_modules()
98 {
99 // Create a module for every track, playable or not
100         Track *current = renderengine->get_edl()->tracks->first;
101         int module = 0;
102 // printf("CommonRender::create_modules %d modules=%p total_modules=%d\n",
103 // __LINE__,
104 // modules,
105 // total_modules);
106
107         if(!modules)
108         {
109                 total_modules = get_total_tracks();
110                 modules = new Module*[total_modules];
111
112 // printf("CommonRender::create_modules %d total_modules=%d\n",
113 // __LINE__,
114 // total_modules);
115                 for(module = 0; module < total_modules && current; current = NEXT)
116                 {
117                         if(current->data_type == data_type)
118                         {
119                                 modules[module] = new_module(current);
120                                 modules[module]->create_objects();
121                                 module++;
122                         }
123                 }
124         }
125         else
126 // Update changes in plugins for existing modules
127         {
128                 for(module = 0; module < total_modules; module++)
129                 {
130                         modules[module]->create_objects();
131                 }
132         }
133 }
134
135 void CommonRender::start_plugins()
136 {
137 // Only start if virtual console was created
138         if(restart_plugins)
139         {
140                 for(int i = 0; i < total_modules; i++)
141                 {
142                         modules[i]->render_init();
143                 }
144         }
145 }
146
147 void CommonRender::stop_plugins()
148 {
149         for(int i = 0; i < total_modules; i++)
150         {
151                 modules[i]->render_stop();
152         }
153 }
154
155 int CommonRender::test_reconfigure(int64_t position, int64_t &length)
156 {
157         if(!vconsole) return 1;
158         if(!modules) return 1;
159
160         return vconsole->test_reconfigure(position, length);
161 }
162
163
164 void CommonRender::build_virtual_console()
165 {
166 // Create new virtual console object
167         if(!vconsole)
168         {
169                 vconsole = new_vconsole_object();
170         }
171
172 // Create nodes
173         vconsole->create_objects();
174 }
175
176 void CommonRender::start_command()
177 {
178         if(renderengine->command->realtime)
179         {
180                 Thread::set_realtime(renderengine->get_edl()->session->real_time_playback &&
181                         data_type == TRACK_AUDIO);
182                 Thread::start();
183                 start_lock->lock("CommonRender::start_command");
184         }
185 }
186
187 void CommonRender::interrupt_playback()
188 {
189         interrupt = 1;
190 }
191
192 int CommonRender::restart_playback()
193 {
194 //printf("CommonRender::restart_playback %d\n", __LINE__);
195         delete_vconsole();
196         create_modules();
197         build_virtual_console();
198 //vconsole->dump();
199         start_plugins();
200 //printf("CommonRender::restart_playback %d\n", __LINE__);
201
202         done = 0;
203         interrupt = 0;
204         restart_plugins = 0;
205         return 0;
206 }
207
208 void CommonRender::delete_vconsole()
209 {
210         if(vconsole) delete vconsole;
211         vconsole = 0;
212 }
213
214 int CommonRender::get_boundaries(int64_t &current_render_length)
215 {
216         int64_t loop_end = tounits(renderengine->get_edl()->local_session->loop_end, 1);
217         int64_t loop_start = tounits(renderengine->get_edl()->local_session->loop_start, 0);
218         int64_t start_position = tounits(renderengine->command->start_position, 0);
219         int64_t end_position = tounits(renderengine->command->end_position, 1);
220
221
222 // test absolute boundaries if no loop and not infinite
223         if(renderengine->command->single_frame() ||
224                 (!renderengine->get_edl()->local_session->loop_playback &&
225                 !renderengine->command->infinite))
226         {
227                 if(renderengine->command->get_direction() == PLAY_FORWARD)
228                 {
229                         if(current_position + current_render_length >= end_position)
230                         {
231                                 current_render_length = end_position - current_position;
232                                 if(current_render_length <= 0) done = 1;
233                         }
234                 }
235 // reverse playback
236                 else
237                 {
238                         if(current_position - current_render_length <= start_position)
239                         {
240                                 current_render_length = current_position - start_position;
241                                 if(current_render_length <= 0) done = 1;
242                         }
243                 }
244         }
245
246 // test against loop boundaries
247         if(!renderengine->command->single_frame() &&
248                 renderengine->get_edl()->local_session->loop_playback &&
249                 !renderengine->command->infinite)
250         {
251                 if(renderengine->command->get_direction() == PLAY_FORWARD)
252                 {
253                         int64_t segment_end = current_position + current_render_length;
254                         if(segment_end > loop_end)
255                         {
256                                 current_render_length = loop_end - current_position;
257                         }
258                 }
259                 else
260                 {
261                         int64_t segment_end = current_position - current_render_length;
262                         if(segment_end < loop_start)
263                         {
264                                 current_render_length = current_position - loop_start;
265                         }
266                 }
267         }
268
269         if(renderengine->command->single_frame())
270                 current_render_length = 1;
271
272         if(current_render_length < 0) current_render_length = 0;
273         return 0;
274 }
275
276 void CommonRender::run()
277 {
278         start_lock->unlock();
279 }
280
281 int64_t CommonRender::tounits(double position, int round)
282 {
283         return (int64_t)position;
284 }
285
286 double CommonRender::fromunits(int64_t position)
287 {
288         return (double)position;
289 }
290
291 int CommonRender::advance_position(int64_t current_render_length)
292 {
293         int64_t loop_end = tounits(renderengine->get_edl()->local_session->loop_end, 1);
294         int64_t loop_start = tounits(renderengine->get_edl()->local_session->loop_start, 0);
295         int64_t start_position = tounits(renderengine->command->start_position, 0);
296         int64_t end_position = tounits(renderengine->command->end_position, 1);
297         int direction = renderengine->command->get_direction();
298
299 // advance the playback position
300         if(direction == PLAY_REVERSE)
301                 current_position -= current_render_length;
302         else
303                 current_position += current_render_length;
304
305 // test loop again
306         if(renderengine->get_edl()->local_session->loop_playback &&
307                 !renderengine->command->infinite)
308         {
309                 if(direction == PLAY_REVERSE)
310                 {
311                         if(current_position <= loop_start)
312                                 current_position = loop_end;
313                 }
314                 else
315                 {
316                         if(current_position >= loop_end)
317                                 current_position = loop_start + (current_position - loop_end);
318                 }
319         }
320         else
321 // test end of file again
322         {
323                 if( (direction == PLAY_FORWARD && current_position >= end_position) ||
324                         (direction == PLAY_REVERSE && current_position <= start_position) )
325                         done = 1;
326         }
327
328         return 0;
329 }
330
331