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