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