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