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