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