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