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