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