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