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