improve resize flash operation, fixup xv grab/ungrab, fixup label updates
[goodguy/history.git] / cinelerra-5.1 / cinelerra / render.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 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 "arender.h"
23 #include "asset.h"
24 #include "auto.h"
25 #include "awindow.h"
26 #include "awindowgui.h"
27 #include "batchrender.h"
28 #include "bcprogressbox.h"
29 #include "bcsignals.h"
30 #include "cache.h"
31 #include "clip.h"
32 #include "compresspopup.h"
33 #include "condition.h"
34 #include "confirmsave.h"
35 #include "cwindowgui.h"
36 #include "cwindow.h"
37 #include "bchash.h"
38 #include "edits.h"
39 #include "edl.h"
40 #include "edlsession.h"
41 #include "errorbox.h"
42 #include "file.h"
43 #include "filesystem.h"
44 #include "filexml.h"
45 #include "formatcheck.h"
46 #include "formatpopup.h"
47 #include "formattools.h"
48 #include "indexable.h"
49 #include "labels.h"
50 #include "language.h"
51 #include "loadmode.h"
52 #include "localsession.h"
53 #include "mainprogress.h"
54 #include "mainsession.h"
55 #include "mainundo.h"
56 #include "module.h"
57 #include "mutex.h"
58 #include "mwindowgui.h"
59 #include "mwindow.h"
60 #include "packagedispatcher.h"
61 #include "packagerenderer.h"
62 #include "patchbay.h"
63 #include "playabletracks.h"
64 #include "preferences.h"
65 #include "preferencesthread.h"
66 #include "renderfarm.h"
67 #include "render.h"
68 #include "renderprofiles.h"
69 #include "statusbar.h"
70 #include "theme.h"
71 #include "timebar.h"
72 #include "tracks.h"
73 #include "transportque.h"
74 #include "vedit.h"
75 #include "vframe.h"
76 #include "videoconfig.h"
77 #include "vrender.h"
78
79 #include <ctype.h>
80 #include <string.h>
81
82
83
84 RenderItem::RenderItem(MWindow *mwindow)
85  : BC_MenuItem(_("Render..."), _("Shift-R"), 'R')
86 {
87         this->mwindow = mwindow;
88         set_shift(1);
89 }
90
91 int RenderItem::handle_event()
92 {
93         mwindow->gui->unlock_window();
94         mwindow->render->start_interactive();
95         mwindow->gui->lock_window("RenderItem::handle_event");
96         return 1;
97 }
98
99
100
101
102
103
104
105
106
107
108 RenderProgress::RenderProgress(MWindow *mwindow, Render *render)
109  : Thread(1, 0, 0)
110 {
111         this->mwindow = mwindow;
112         this->render = render;
113         last_value = 0;
114         Thread::set_synchronous(1);
115 }
116
117 RenderProgress::~RenderProgress()
118 {
119         Thread::cancel();
120         Thread::join();
121 }
122
123
124 void RenderProgress::run()
125 {
126         Thread::disable_cancel();
127         while(1)
128         {
129                 if(render->total_rendered != last_value)
130                 {
131                         render->progress->update(render->total_rendered);
132                         last_value = render->total_rendered;
133
134                         if(mwindow) mwindow->preferences_thread->update_rates();
135                 }
136
137                 Thread::enable_cancel();
138                 sleep(1);
139                 Thread::disable_cancel();
140         }
141 }
142
143
144
145 MainPackageRenderer::MainPackageRenderer(Render *render)
146  : PackageRenderer()
147 {
148         this->render = render;
149 }
150
151
152
153 MainPackageRenderer::~MainPackageRenderer()
154 {
155 }
156
157
158 int MainPackageRenderer::get_master()
159 {
160         return 1;
161 }
162
163 int MainPackageRenderer::get_result()
164 {
165         return render->result;
166 }
167
168 void MainPackageRenderer::set_result(int value)
169 {
170         if(value)
171                 render->result = value;
172
173
174
175 }
176
177 void MainPackageRenderer::set_progress(int64_t value)
178 {
179         render->counter_lock->lock("MainPackageRenderer::set_progress");
180 // Increase total rendered for all nodes
181         render->total_rendered += value;
182
183 // Update frames per second for master node
184         render->preferences->set_rate(frames_per_second, -1);
185
186 //printf("MainPackageRenderer::set_progress %d %ld %f\n", __LINE__, (long)value, frames_per_second);
187
188 // If non interactive, print progress out
189         if(!render->progress)
190         {
191                 int64_t current_eta = render->progress_timer->get_scaled_difference(1000);
192                 if(current_eta - render->last_eta > 1000)
193                 {
194                         double eta = 0;
195
196
197                         if(render->total_rendered)
198                         {
199                                 eta = current_eta /
200                                         1000 *
201                                         render->progress_max /
202                                         render->total_rendered -
203                                         current_eta /
204                                         1000;
205                         }
206
207                         char string[BCTEXTLEN];
208                         Units::totext(string,
209                                 eta,
210                                 TIME_HMS2);
211
212                         printf("\r%d%% %s: %s      ",
213                                 (int)(100 * (float)render->total_rendered / render->progress_max),
214                                 _("ETA"), string);
215                         fflush(stdout);
216                         render->last_eta = current_eta;
217                 }
218         }
219
220         render->counter_lock->unlock();
221
222 // This locks the preferences
223         if(mwindow) mwindow->preferences->copy_rates_from(preferences);
224 }
225
226 int MainPackageRenderer::progress_cancelled()
227 {
228         return (render->progress && render->progress->is_cancelled()) ||
229                 render->batch_cancelled;
230 }
231
232
233 Render::Render(MWindow *mwindow)
234  : BC_DialogThread()
235 {
236         this->mwindow = mwindow;
237         in_progress = 0;
238         progress = 0;
239         preferences = 0;
240         elapsed_time = 0.0;
241         package_lock = new Mutex("Render::package_lock");
242         counter_lock = new Mutex("Render::counter_lock");
243         completion = new Condition(0, "Render::completion");
244         progress_timer = new Timer;
245         range_type = RANGE_BACKCOMPAT;
246         thread = new RenderThread(mwindow, this);
247         render_window = 0;
248         asset = 0;
249         result = 0;
250 }
251
252 Render::~Render()
253 {
254         close_window();
255         delete package_lock;
256         delete counter_lock;
257         delete completion;
258 // May be owned by someone else.  This is owned by mwindow, so we don't care
259 // about deletion.
260 //      delete preferences;
261         delete progress_timer;
262         if( asset ) asset->Garbage::remove_user();
263         delete thread;
264 }
265
266 void Render::start_interactive()
267 {
268         if( !thread->running() ) {
269                 mode = Render::INTERACTIVE;
270                 BC_DialogThread::start();
271         }
272         else if( in_progress ) {
273                 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
274                         mwindow->gui->get_abs_cursor_x(1),
275                         mwindow->gui->get_abs_cursor_y(1));
276                 error_box.create_objects(_("Already rendering"));
277                 error_box.raise_window();
278                 error_box.run_window();
279         }
280         else if( render_window ) {
281                 render_window->raise_window();
282         }
283 }
284
285
286 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs)
287 {
288         if(!thread->running())
289         {
290                 mode = Render::BATCH;
291                 batch_cancelled = 0;
292                 this->jobs = jobs;
293                 completion->reset();
294                 start_render();
295         }
296         else if( in_progress ) {
297                 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
298                                    mwindow->gui->get_abs_cursor_x(1),
299                                    mwindow->gui->get_abs_cursor_y(1));
300                 error_box.create_objects("Already rendering");
301                 error_box.raise_window();
302                 error_box.run_window();
303         }
304         // raise the window if rendering hasn't started yet
305         else if( render_window ) {
306                 render_window->raise_window();
307         }
308 }
309
310 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs,
311         BC_Hash *boot_defaults,
312         Preferences *preferences)
313 {
314         mode = Render::BATCH;
315         batch_cancelled = 0;
316         this->jobs = jobs;
317         this->preferences = preferences;
318
319         completion->reset();
320 PRINT_TRACE
321         thread->run();
322 PRINT_TRACE
323         this->preferences = 0;
324 }
325
326
327 BC_Window* Render::new_gui()
328 {
329         this->jobs = 0;
330         batch_cancelled = 0;
331         format_error = 0;
332         result = 0;
333         completion->reset();
334
335         if(mode == Render::INTERACTIVE) {
336 // Fix the asset for rendering
337                 if(!asset) asset = new Asset;
338                 load_defaults(asset);
339                 check_asset(mwindow->edl, *asset);
340
341 // Get format from user
342                 render_window = new RenderWindow(mwindow,
343                         this,
344                         asset,
345                         mwindow->gui->get_abs_cursor_x(1),
346                         mwindow->gui->get_abs_cursor_y(1));
347                 render_window->create_objects();
348         }
349
350         return render_window;
351 }
352
353 void Render::handle_done_event(int result)
354 {
355         if(!result) {
356                 // add to recentlist only on OK
357                 render_window->format_tools->path_recent->
358                         add_item(File::formattostr(asset->format), asset->path);
359         }
360         render_window = 0;
361 }
362
363 void Render::handle_close_event(int result)
364 {
365         int format_error = 0;
366         const int debug = 0;
367
368         if(!result) {
369 // Check the asset format for errors.
370                 FormatCheck format_check(asset);
371                 format_error = format_check.check_format();
372         }
373
374 //PRINT_TRACE
375
376         save_defaults(asset);
377 //PRINT_TRACE
378         mwindow->save_defaults();
379 //PRINT_TRACE
380
381         if(!format_error && !result)
382         {
383                 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
384                 if(!result) start_render();
385                 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
386         }
387 //PRINT_TRACE
388 }
389
390
391
392 void Render::stop_operation()
393 {
394         if(thread->Thread::running())
395         {
396                 batch_cancelled = 1;
397 // Wait for completion
398                 completion->lock("Render::stop_operation");
399                 completion->reset();
400         }
401 }
402
403
404
405 int Render::check_asset(EDL *edl, Asset &asset)
406 {
407         if(asset.video_data &&
408                 edl->tracks->playable_video_tracks() &&
409                 File::supports_video(asset.format))
410         {
411                 asset.video_data = 1;
412                 asset.layers = 1;
413                 asset.width = edl->session->output_w;
414                 asset.height = edl->session->output_h;
415                 asset.interlace_mode = edl->session->interlace_mode;
416                 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
417                         edl->local_session->get_selectionstart() *
418                                 edl->session->frame_rate);
419                 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
420                         edl->local_session->get_selectionend() *
421                                 edl->session->frame_rate);
422         }
423         else
424         {
425                 asset.video_data = 0;
426                 asset.layers = 0;
427                 asset.tcstart = 0;
428                 asset.tcend = 0;
429         }
430
431         if(asset.audio_data &&
432                 edl->tracks->playable_audio_tracks() &&
433                 File::supports_audio(asset.format))
434         {
435                 asset.audio_data = 1;
436                 asset.channels = edl->session->audio_channels;
437                 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
438                         edl->local_session->get_selectionstart() *
439                                 edl->session->sample_rate);
440                 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
441                         edl->local_session->get_selectionend() *
442                                 edl->session->sample_rate);
443         }
444         else
445         {
446                 asset.audio_data = 0;
447                 asset.channels = 0;
448                 asset.tcstart = 0;
449                 asset.tcend = 0;
450         }
451
452         if(!asset.audio_data &&
453                 !asset.video_data)
454         {
455                 return 1;
456         }
457         return 0;
458 }
459
460 int Render::fix_strategy(int strategy, int use_renderfarm)
461 {
462         if(use_renderfarm)
463         {
464                 if(strategy == FILE_PER_LABEL)
465                         strategy = FILE_PER_LABEL_FARM;
466                 else
467                 if(strategy == SINGLE_PASS)
468                         strategy = SINGLE_PASS_FARM;
469         }
470         else
471         {
472                 if(strategy == FILE_PER_LABEL_FARM)
473                         strategy = FILE_PER_LABEL;
474                 else
475                 if(strategy == SINGLE_PASS_FARM)
476                         strategy = SINGLE_PASS;
477         }
478         return strategy;
479 }
480
481 void Render::start_progress()
482 {
483         char filename[BCTEXTLEN];
484         char string[BCTEXTLEN];
485         FileSystem fs;
486
487         progress_max = packages->get_progress_max();
488
489         progress_timer->update();
490         last_eta = 0;
491         if(mwindow)
492         {
493 // Generate the progress box
494                 fs.extract_name(filename, default_asset->path);
495                 sprintf(string, _("Rendering %s..."), filename);
496
497 // Don't bother with the filename since renderfarm defeats the meaning
498                 progress = mwindow->mainprogress->start_progress(_("Rendering..."),
499                         progress_max);
500                 render_progress = new RenderProgress(mwindow, this);
501                 render_progress->start();
502         }
503 }
504
505 void Render::stop_progress()
506 {
507         if(progress)
508         {
509                 char string[BCTEXTLEN], string2[BCTEXTLEN];
510                 delete render_progress;
511                 progress->get_time(string);
512                 elapsed_time = progress->get_time();
513                 progress->stop_progress();
514                 delete progress;
515
516                 sprintf(string2, _("Rendering took %s"), string);
517                 mwindow->gui->lock_window("");
518                 mwindow->gui->show_message(string2);
519                 mwindow->gui->stop_hourglass();
520                 mwindow->gui->unlock_window();
521         }
522         progress = 0;
523 }
524
525
526
527 void Render::start_render()
528 {
529         in_progress = 0;
530         elapsed_time = 0.0;
531         result = 0;
532         thread->start();
533 }
534
535
536 void Render::create_filename(char *path,
537         char *default_path,
538         int current_number,
539         int total_digits,
540         int number_start)
541 {
542         int i, j;
543         int len = strlen(default_path);
544         char printf_string[BCTEXTLEN];
545
546         for(i = 0, j = 0; i < number_start; i++, j++)
547         {
548                 printf_string[j] = default_path[i];
549         }
550
551 // Found the number
552         sprintf(&printf_string[j], "%%0%dd", total_digits);
553         j = strlen(printf_string);
554         i += total_digits;
555
556 // Copy remainder of string
557         for( ; i < len; i++, j++)
558         {
559                 printf_string[j] = default_path[i];
560         }
561         printf_string[j] = 0;
562 // Print the printf argument to the path
563         sprintf(path, printf_string, current_number);
564 }
565
566 void Render::get_starting_number(char *path,
567         int &current_number,
568         int &number_start,
569         int &total_digits,
570         int min_digits)
571 {
572         int len = strlen(path);
573         char number_text[BCTEXTLEN];
574         char *ptr = 0;
575         char *ptr2 = 0;
576
577         total_digits = 0;
578         number_start = 0;
579
580 // Search for last /
581         ptr2 = strrchr(path, '/');
582
583 // Search for first 0 after last /.
584         if(ptr2)
585                 ptr = strchr(ptr2, '0');
586
587         if(ptr && isdigit(*ptr))
588         {
589                 number_start = ptr - path;
590
591 // Store the first number
592                 char *ptr2 = number_text;
593                 while(isdigit(*ptr))
594                         *ptr2++ = *ptr++;
595                 *ptr2++ = 0;
596                 current_number = atol(number_text);
597                 total_digits = strlen(number_text);
598         }
599
600
601 // No number found or number not long enough
602         if(total_digits < min_digits)
603         {
604                 current_number = 1;
605                 number_start = len;
606                 total_digits = min_digits;
607         }
608 }
609
610
611 int Render::load_defaults(Asset *asset)
612 {
613         strategy = mwindow->defaults->get("RENDER_STRATEGY", SINGLE_PASS);
614         load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOADMODE_NEW_TRACKS);
615         range_type = mwindow->defaults->get("RENDER_RANGE_TYPE", RANGE_PROJECT);
616
617 // some defaults which work
618         asset->video_data = 1;
619         asset->audio_data = 1;
620         asset->format = FILE_FFMPEG;
621         strcpy(asset->acodec, "mp4.qt");
622         strcpy(asset->vcodec, "mp4.qt");
623
624         asset->load_defaults(mwindow->defaults,
625                 "RENDER_", 1, 1, 1, 1, 1);
626         return 0;
627 }
628
629 int Render::load_profile(int profile_slot, Asset *asset)
630 {
631         char string_name[100];
632         sprintf(string_name, "RENDER_%i_STRATEGY", profile_slot);
633         strategy = mwindow->defaults->get(string_name, SINGLE_PASS);
634 // Load mode is not part of the profile
635 //      printf(string_name, "RENDER_%i_LOADMODE", profile_slot);
636 //      load_mode = mwindow->defaults->get(string_name, LOADMODE_NEW_TRACKS);
637         sprintf(string_name, "RENDER_%i_RANGE_TYPE", profile_slot);
638         range_type = mwindow->defaults->get(string_name, RANGE_PROJECT);
639
640         sprintf(string_name, "RENDER_%i_", profile_slot);
641         asset->load_defaults(mwindow->defaults,
642                 string_name, 1, 1, 1, 1, 1);
643         return 0;
644 }
645
646
647 int Render::save_defaults(Asset *asset)
648 {
649         mwindow->defaults->update("RENDER_STRATEGY", strategy);
650         mwindow->defaults->update("RENDER_LOADMODE", load_mode);
651         mwindow->defaults->update("RENDER_RANGE_TYPE", range_type);
652
653         asset->save_defaults(mwindow->defaults,
654                 "RENDER_", 1, 1, 1, 1, 1);
655         return 0;
656 }
657
658
659 static void run_script(const char *script, const char *arg)
660 {
661         char *const argv[] = { (char*)script, (char*)arg, 0 };
662         execvp(script ,&argv[0]);
663         perror("execvp script failed");
664         exit(1);
665 }
666
667 RenderThread::RenderThread(MWindow *mwindow, Render *render)
668  : Thread(0, 0, 0)
669 {
670         this->mwindow = mwindow;
671         this->render = render;
672 }
673
674 RenderThread::~RenderThread()
675 {
676 }
677
678
679 void RenderThread::render_single(int test_overwrite,
680         Asset *asset,
681         EDL *edl,
682         int strategy,
683         int range_type)
684 {
685 // Total length in seconds
686         double total_length;
687         RenderFarmServer *farm_server = 0;
688         FileSystem fs;
689         //int done = 0;
690         const int debug = 0;
691
692         render->in_progress = 1;
693
694
695         render->default_asset = asset;
696         render->progress = 0;
697         render->result = 0;
698
699         if(mwindow)
700         {
701                 if(!render->preferences)
702                         render->preferences = new Preferences;
703
704                 render->preferences->copy_from(mwindow->preferences);
705         }
706
707
708 // Create rendering command
709         TransportCommand *command = new TransportCommand;
710         command->command = NORMAL_FWD;
711         command->get_edl()->copy_all(edl);
712         command->change_type = CHANGE_ALL;
713
714         if (range_type == RANGE_BACKCOMPAT) {
715 // Get highlighted playback range
716                 command->set_playback_range();
717 // Adjust playback range with in/out points
718                 command->playback_range_adjust_inout();
719         }
720         else if (range_type == RANGE_PROJECT) {
721                 command->playback_range_project();
722         }
723         else if (range_type == RANGE_SELECTION) {
724                 command->set_playback_range();
725         }
726         else if (range_type == RANGE_INOUT) {
727                 command->playback_range_inout();
728         }
729
730         render->packages = new PackageDispatcher;
731
732 // Create caches
733         CICache *audio_cache = new CICache(render->preferences);
734         CICache *video_cache = new CICache(render->preferences);
735
736         render->default_asset->frame_rate = command->get_edl()->session->frame_rate;
737         render->default_asset->sample_rate = command->get_edl()->session->sample_rate;
738
739 // Conform asset to EDL.  Find out if any tracks are playable.
740         render->result = render->check_asset(command->get_edl(),
741                 *render->default_asset);
742
743         if(!render->result)
744         {
745 // Get total range to render
746                 render->total_start = command->start_position;
747                 render->total_end = command->end_position;
748                 total_length = render->total_end - render->total_start;
749
750 // Nothing to render
751                 if(EQUIV(total_length, 0))
752                 {
753                         render->result = 1;
754                 }
755         }
756
757 // Generate packages
758         if(!render->result)
759         {
760 // Stop background rendering
761                 if(mwindow) mwindow->stop_brender();
762
763                 fs.complete_path(render->default_asset->path);
764                 strategy = Render::fix_strategy(strategy, render->preferences->use_renderfarm);
765
766                 render->result = render->packages->create_packages(mwindow,
767                         command->get_edl(),
768                         render->preferences,
769                         strategy,
770                         render->default_asset,
771                         render->total_start,
772                         render->total_end,
773                         test_overwrite);
774         }
775
776         //done = 0;
777         render->total_rendered = 0;
778
779         if(!render->result)
780         {
781 // Start dispatching external jobs
782                 if(mwindow)
783                 {
784                         mwindow->gui->lock_window("Render::render 1");
785                         mwindow->gui->show_message(_("Starting render farm"));
786                         mwindow->gui->start_hourglass();
787                         mwindow->gui->unlock_window();
788                 }
789                 else
790                 {
791                         printf("Render::render: starting render farm\n");
792                 }
793
794                 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
795                 {
796                         farm_server = new RenderFarmServer(mwindow,
797                                 render->packages,
798                                 render->preferences,
799                                 1,
800                                 &render->result,
801                                 &render->total_rendered,
802                                 render->counter_lock,
803                                 render->default_asset,
804                                 command->get_edl(),
805                                 0);
806                         render->result = farm_server->start_clients();
807
808                         if(render->result)
809                         {
810                                 if(mwindow)
811                                 {
812                                         mwindow->gui->lock_window("Render::render 2");
813                                         mwindow->gui->show_message(_("Failed to start render farm"),
814                                                 mwindow->theme->message_error);
815                                         mwindow->gui->stop_hourglass();
816                                         mwindow->gui->unlock_window();
817                                 }
818                                 else
819                                 {
820                                         printf("Render::render: Failed to start render farm\n");
821                                 }
822                         }
823                 }
824         }
825
826 // Perform local rendering
827
828
829         if(!render->result)
830         {
831                 render->start_progress();
832
833
834
835
836                 MainPackageRenderer package_renderer(render);
837                 render->result = package_renderer.initialize(mwindow,
838                                 command->get_edl(),   // Copy of master EDL
839                                 render->preferences,
840                                 render->default_asset);
841
842
843
844
845
846
847
848                 while(!render->result)
849                 {
850 // Get unfinished job
851                         RenderPackage *package;
852
853                         if(strategy == SINGLE_PASS_FARM)
854                         {
855                                 package = render->packages->get_package(
856                                         package_renderer.frames_per_second,
857                                         -1,
858                                         1);
859                         }
860                         else
861                         {
862                                 package = render->packages->get_package(0, -1, 1);
863                         }
864
865 // Exit point
866                         if(!package)
867                         {
868                                 //done = 1;
869                                 break;
870                         }
871
872
873
874                         Timer timer;
875                         timer.update();
876
877                         if(package_renderer.render_package(package))
878                                 render->result = 1;
879
880
881                 } // file_number
882
883
884
885 printf("Render::render_single: Session finished.\n");
886
887
888
889
890
891                 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
892                 {
893                         farm_server->wait_clients();
894                         render->result |= render->packages->packages_are_done();
895                 }
896
897 if(debug) printf("Render::render %d\n", __LINE__);
898
899 // Notify of error
900                 if(render->result &&
901                         (!render->progress || !render->progress->is_cancelled()) &&
902                         !render->batch_cancelled)
903                 {
904 if(debug) printf("Render::render %d\n", __LINE__);
905                         if(mwindow)
906                         {
907 if(debug) printf("Render::render %d\n", __LINE__);
908                                 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
909                                         mwindow->gui->get_abs_cursor_x(1),
910                                         mwindow->gui->get_abs_cursor_y(1));
911                                 error_box.create_objects(_("Error rendering data."));
912                                 error_box.raise_window();
913                                 error_box.run_window();
914 if(debug) printf("Render::render %d\n", __LINE__);
915                         }
916                         else
917                         {
918                                 printf("Render::render: Error rendering data\n");
919                         }
920                 }
921 if(debug) printf("Render::render %d\n", __LINE__);
922
923 // Delete the progress box
924                 render->stop_progress();
925
926 if(debug) printf("Render::render %d\n", __LINE__);
927         }
928
929
930 // Paste all packages into timeline if desired
931
932         if(!render->result &&
933                 render->load_mode != LOADMODE_NOTHING &&
934                 mwindow &&
935                 render->mode != Render::BATCH)
936         {
937 if(debug) printf("Render::render %d\n", __LINE__);
938                 mwindow->gui->lock_window("Render::render 3");
939 if(debug) printf("Render::render %d\n", __LINE__);
940
941                 mwindow->undo->update_undo_before();
942
943 if(debug) printf("Render::render %d\n", __LINE__);
944
945
946                 ArrayList<Indexable*> *assets = render->packages->get_asset_list();
947 if(debug) printf("Render::render %d\n", __LINE__);
948                 if(render->load_mode == LOADMODE_PASTE)
949                         mwindow->clear(0);
950 if(debug) printf("Render::render %d\n", __LINE__);
951                 mwindow->load_assets(assets,
952                         -1,
953                         render->load_mode,
954                         0,
955                         0,
956                         mwindow->edl->session->labels_follow_edits,
957                         mwindow->edl->session->plugins_follow_edits,
958                         mwindow->edl->session->autos_follow_edits,
959                         0); // overwrite
960 if(debug) printf("Render::render %d\n", __LINE__);
961                 for(int i = 0; i < assets->size(); i++)
962                         assets->get(i)->Garbage::remove_user();
963                 delete assets;
964 if(debug) printf("Render::render %d\n", __LINE__);
965
966
967                 mwindow->save_backup();
968 if(debug) printf("Render::render %d\n", __LINE__);
969                 mwindow->undo->update_undo_after(_("render"), LOAD_ALL);
970 if(debug) printf("Render::render %d\n", __LINE__);
971                 mwindow->update_plugin_guis();
972 if(debug) printf("Render::render %d\n", __LINE__);
973                 mwindow->gui->update(1,
974                         2,
975                         1,
976                         1,
977                         1,
978                         1,
979                         0);
980 if(debug) printf("Render::render %d\n", __LINE__);
981                 mwindow->sync_parameters(CHANGE_ALL);
982 if(debug) printf("Render::render %d\n", __LINE__);
983                 mwindow->gui->unlock_window();
984
985
986                 mwindow->awindow->gui->async_update_assets();
987
988 if(debug) printf("Render::render %d\n", __LINE__);
989         }
990
991 if(debug) printf("Render::render %d\n", __LINE__);
992
993 // Disable hourglass
994         if(mwindow)
995         {
996                 mwindow->gui->lock_window("Render::render 3");
997                 mwindow->gui->stop_hourglass();
998                 mwindow->gui->unlock_window();
999         }
1000
1001 //printf("Render::render 110\n");
1002 // Need to restart because brender always stops before render.
1003         if(mwindow)
1004                 mwindow->restart_brender();
1005         if(farm_server) delete farm_server;
1006         delete command;
1007         delete audio_cache;
1008         delete video_cache;
1009 // Must delete packages after server
1010         delete render->packages;
1011
1012         render->packages = 0;
1013         render->in_progress = 0;
1014         render->completion->unlock();
1015 if(debug) printf("Render::render %d\n", __LINE__);
1016 }
1017
1018 void RenderThread::run()
1019 {
1020         if(render->mode == Render::INTERACTIVE)
1021         {
1022                 render_single(1, render->asset, mwindow->edl, render->strategy, render->range_type);
1023         }
1024         else
1025         if(render->mode == Render::BATCH)
1026         {
1027 // PRINT_TRACE
1028 // printf("RenderThread::run %d %d %d\n",
1029 // __LINE__,
1030 // render->jobs->total,
1031 // render->result);
1032                 for(int i = 0; i < render->jobs->total && !render->result; i++)
1033                 {
1034 //PRINT_TRACE
1035                         BatchRenderJob *job = render->jobs->values[i];
1036 //PRINT_TRACE
1037                         if(job->enabled)
1038                         {
1039                                 if( *job->edl_path == '@' )
1040                                 {
1041                                         run_script(job->edl_path+1, job->asset->path);
1042                                 }
1043
1044                                 if(mwindow)
1045                                 {
1046                                         mwindow->batch_render->update_active(i);
1047                                 }
1048                                 else
1049                                 {
1050                                         printf("Render::run: %s\n", job->edl_path);
1051                                 }
1052
1053 //PRINT_TRACE
1054
1055                                 FileXML *file = new FileXML;
1056                                 EDL *edl = new EDL;
1057                                 edl->create_objects();
1058                                 file->read_from_file(job->edl_path);
1059                                 edl->load_xml(file, LOAD_ALL);
1060
1061 //PRINT_TRACE
1062                                 render_single(0, job->asset, edl, job->strategy, RANGE_BACKCOMPAT);
1063
1064 //PRINT_TRACE
1065                                 edl->Garbage::remove_user();
1066                                 delete file;
1067                                 if(!render->result)
1068                                 {
1069                                         if(mwindow)
1070                                                 mwindow->batch_render->update_done(i, 1, render->elapsed_time);
1071                                         else
1072                                         {
1073                                                 char string[BCTEXTLEN];
1074                                                 render->elapsed_time =
1075                                                         (double)render->progress_timer->get_scaled_difference(1);
1076                                                 Units::totext(string,
1077                                                         render->elapsed_time,
1078                                                         TIME_HMS2);
1079                                                 printf("Render::run: done in %s\n", string);
1080                                         }
1081                                 }
1082                                 else
1083                                 {
1084                                         if(mwindow)
1085                                                 mwindow->batch_render->update_active(-1);
1086                                         else
1087                                                 printf("Render::run: failed\n");
1088                                 }
1089                         }
1090 //PRINT_TRACE
1091                 }
1092
1093                 if(mwindow)
1094                 {
1095                         mwindow->batch_render->update_active(-1);
1096                         mwindow->batch_render->update_done(-1, 0, 0);
1097                 }
1098         }
1099 }
1100
1101
1102 #define WIDTH 440
1103 #define HEIGHT 455
1104
1105
1106 RenderWindow::RenderWindow(MWindow *mwindow,
1107         Render *render,
1108         Asset *asset,
1109         int x,
1110         int y)
1111  : BC_Window(_(PROGRAM_NAME ": Render"),
1112         x - WIDTH / 2, y - HEIGHT / 2,
1113         WIDTH, HEIGHT, WIDTH, HEIGHT,
1114         0, 0, 1)
1115 {
1116         this->mwindow = mwindow;
1117         this->render = render;
1118         this->asset = asset;
1119 }
1120
1121 RenderWindow::~RenderWindow()
1122 {
1123 SET_TRACE
1124         lock_window("RenderWindow::~RenderWindow");
1125 SET_TRACE
1126         delete format_tools;
1127 SET_TRACE
1128         delete loadmode;
1129 SET_TRACE
1130         unlock_window();
1131 SET_TRACE
1132 }
1133
1134
1135 void RenderWindow::load_profile(int profile_slot)
1136 {
1137         render->load_profile(profile_slot, asset);
1138         update_range_type(render->range_type);
1139         format_tools->update(asset, &render->strategy);
1140 }
1141
1142
1143 void RenderWindow::create_objects()
1144 {
1145         int x = 10, y = 5;
1146         lock_window("RenderWindow::create_objects");
1147         add_subwindow(new BC_Title(x,
1148                 y,
1149                 (char*)((render->strategy == FILE_PER_LABEL ||
1150                                 render->strategy == FILE_PER_LABEL_FARM) ?
1151                         _("Select the first file to render to:") :
1152                         _("Select a file to render to:"))));
1153         y += 25;
1154
1155         format_tools = new FormatTools(mwindow, this, asset);
1156         format_tools->create_objects(x, y,
1157                 1, 1, 1, 1, 0, 1, 0, 0, &render->strategy, 0);
1158
1159         add_subwindow(new BC_Title(x, y, _("Render range:")));
1160
1161         x += 110;
1162         add_subwindow(rangeproject = new RenderRangeProject(this,
1163                 render->range_type == RANGE_PROJECT, x, y));
1164         y += 20;
1165         add_subwindow(rangeselection = new RenderRangeSelection(this,
1166                 render->range_type == RANGE_SELECTION, x, y));
1167         y += 20;
1168         add_subwindow(rangeinout = new RenderRangeInOut(this,
1169                 render->range_type == RANGE_INOUT, x, y));
1170         y += 30;
1171         x = 5;
1172
1173         renderprofile = new RenderProfile(mwindow, this, x, y, 1);
1174         renderprofile->create_objects();
1175         y += 70;
1176
1177         loadmode = new LoadMode(mwindow, this, x, y, &render->load_mode, 1);
1178         loadmode->create_objects();
1179
1180         add_subwindow(new BC_OKButton(this));
1181         add_subwindow(new BC_CancelButton(this));
1182         show_window();
1183         unlock_window();
1184 }
1185
1186 void RenderWindow::update_range_type(int range_type)
1187 {
1188         render->range_type = range_type;
1189         rangeproject->update(range_type == RANGE_PROJECT);
1190         rangeselection->update(range_type == RANGE_SELECTION);
1191         rangeinout->update(range_type == RANGE_INOUT);
1192 }
1193
1194
1195 RenderRangeProject::RenderRangeProject(RenderWindow *rwindow, int value, int x, int y)
1196  : BC_Radial(x, y, value, _("Project"))
1197 {
1198         this->rwindow = rwindow;
1199 }
1200 int RenderRangeProject::handle_event()
1201 {
1202         rwindow->update_range_type(RANGE_PROJECT);
1203         return 1;
1204 }
1205
1206 RenderRangeSelection::RenderRangeSelection(RenderWindow *rwindow, int value, int x, int y)
1207  : BC_Radial(x, y, value, _("Selection"))
1208 {
1209         this->rwindow = rwindow;
1210 }
1211 int RenderRangeSelection::handle_event()
1212 {
1213         rwindow->update_range_type(RANGE_SELECTION);
1214         return 1;
1215 }
1216
1217
1218 RenderRangeInOut::RenderRangeInOut(RenderWindow *rwindow, int value, int x, int y)
1219  : BC_Radial(x, y, value, _("In/Out Points"))
1220 {
1221         this->rwindow = rwindow;
1222 }
1223 int RenderRangeInOut::handle_event()
1224 {
1225         rwindow->update_range_type(RANGE_INOUT);
1226         return 1;
1227 }
1228
1229