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