4 #include "batchrender.h"
5 #include "bcprogressbox.h"
8 #include "compresspopup.h"
10 #include "confirmsave.h"
11 #include "cwindowgui.h"
16 #include "edlsession.h"
19 #include "filesystem.h"
21 #include "formatcheck.h"
22 #include "formatpopup.h"
23 #include "formattools.h"
27 #include "localsession.h"
28 #include "mainprogress.h"
29 #include "mainsession.h"
33 #include "mwindowgui.h"
35 #include "packagedispatcher.h"
36 #include "packagerenderer.h"
38 #include "playabletracks.h"
39 #include "preferences.h"
40 #include "quicktime.h"
41 #include "renderfarm.h"
43 #include "statusbar.h"
46 #include "transportque.h"
49 #include "videoconfig.h"
57 RenderItem::RenderItem(MWindow *mwindow)
58 : BC_MenuItem(_("Render..."), "Shift+R", 'R')
60 this->mwindow = mwindow;
64 int RenderItem::handle_event()
66 mwindow->render->start_interactive();
79 RenderProgress::RenderProgress(MWindow *mwindow, Render *render)
82 this->mwindow = mwindow;
83 this->render = render;
85 Thread::set_synchronous(1);
88 RenderProgress::~RenderProgress()
95 void RenderProgress::run()
97 Thread::disable_cancel();
100 if(render->total_rendered != last_value)
102 render->progress->update(render->total_rendered);
103 last_value = render->total_rendered;
106 Thread::enable_cancel();
108 Thread::disable_cancel();
121 MainPackageRenderer::MainPackageRenderer(Render *render)
124 this->render = render;
129 MainPackageRenderer::~MainPackageRenderer()
134 int MainPackageRenderer::get_master()
139 int MainPackageRenderer::get_result()
141 return render->result;
144 void MainPackageRenderer::set_result(int value)
147 render->result = value;
150 void MainPackageRenderer::set_progress(int64_t value)
152 render->counter_lock->lock("MainPackageRenderer::set_progress");
153 render->total_rendered += value;
155 // If non interactive, print progress out
156 if(!render->progress)
158 int64_t current_eta = render->progress_timer->get_scaled_difference(1000);
159 if(current_eta - render->last_eta > 1000)
164 if(render->total_rendered)
168 render->progress_max /
169 render->total_rendered -
174 char string[BCTEXTLEN];
175 Units::totext(string,
179 printf("%d%% ETA: %s \r", (int)(100 *
180 (float)render->total_rendered /
181 render->progress_max),
184 render->last_eta = current_eta;
188 render->counter_lock->unlock();
191 int MainPackageRenderer::progress_cancelled()
193 return (render->progress && render->progress->is_cancelled()) ||
194 render->batch_cancelled;
208 Render::Render(MWindow *mwindow)
211 this->mwindow = mwindow;
212 if(mwindow) plugindb = mwindow->plugindb;
217 package_lock = new Mutex("Render::package_lock");
218 counter_lock = new Mutex("Render::counter_lock");
219 completion = new Condition(0, "Render::completion");
220 progress_timer = new Timer;
228 if(preferences) delete preferences;
229 delete progress_timer;
232 void Render::start_interactive()
234 if(!Thread::running())
236 mode = Render::INTERACTIVE;
244 // raise the window if rendering hasn't started yet
245 if (render_window && ! in_progress) {
246 render_window->raise_window();
249 ErrorBox error_box(PROGRAM_NAME ": Error",
250 mwindow->gui->get_abs_cursor_x(1),
251 mwindow->gui->get_abs_cursor_y(1));
252 error_box.create_objects("Already rendering");
253 error_box.run_window();
258 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs)
261 if(!Thread::running())
263 mode = Render::BATCH;
270 ErrorBox error_box(PROGRAM_NAME ": Error",
271 mwindow->gui->get_abs_cursor_x(1),
272 mwindow->gui->get_abs_cursor_y(1));
273 error_box.create_objects("Already rendering");
274 error_box.run_window();
278 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs,
279 Defaults *boot_defaults,
280 Preferences *preferences,
281 ArrayList<PluginServer*> *plugindb)
283 mode = Render::BATCH;
286 this->preferences = preferences;
287 this->plugindb = plugindb;
291 this->preferences = 0;
294 void Render::stop_operation()
296 if(Thread::running())
299 // Wait for completion
300 completion->lock("Render::stop_operation");
313 if(mode == Render::INTERACTIVE)
315 // Fix the asset for rendering
316 Asset *asset = new Asset;
317 load_defaults(asset);
318 check_asset(mwindow->edl, *asset);
320 // Get format from user
329 render_window = new RenderWindow(mwindow, this, asset);
330 render_window->create_objects();
331 result = render_window->run_window();
333 // add to recentlist only on OK
334 render_window->format_tools->path_recent->add_item(FILE_FORMAT_PREFIX(asset->format), asset->path);
336 delete render_window;
342 // Check the asset format for errors.
343 FormatCheck format_check(asset);
344 format_error = format_check.check_format();
346 }while(format_error && !result);
349 save_defaults(asset);
350 mwindow->save_defaults();
352 if(!result) render(1, asset, mwindow->edl, strategy);
357 if(mode == Render::BATCH)
359 for(int i = 0; i < jobs->total && !result; i++)
361 BatchRenderJob *job = jobs->values[i];
366 mwindow->batch_render->update_active(i);
370 printf("Render::run: %s\n", job->edl_path);
374 FileXML *file = new FileXML;
376 edl->create_objects();
377 file->read_from_file(job->edl_path);
378 if(!plugindb && mwindow)
379 plugindb = mwindow->plugindb;
380 edl->load_xml(plugindb, file, LOAD_ALL);
382 render(0, job->asset, edl, job->strategy);
389 mwindow->batch_render->update_done(i, 1, elapsed_time);
392 char string[BCTEXTLEN];
394 (double)progress_timer->get_scaled_difference(1);
395 Units::totext(string,
398 printf("Render::run: done in %s\n", string);
404 mwindow->batch_render->update_active(-1);
406 printf("Render::run: failed\n");
413 mwindow->batch_render->update_active(-1);
414 mwindow->batch_render->update_done(-1, 0, 0);
421 int Render::check_asset(EDL *edl, Asset &asset)
423 if(asset.video_data &&
424 edl->tracks->playable_video_tracks() &&
425 File::supports_video(asset.format))
427 asset.video_data = 1;
429 asset.width = edl->session->output_w;
430 asset.height = edl->session->output_h;
431 asset.interlace_mode = edl->session->interlace_mode;
432 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
433 edl->local_session->get_selectionstart() *
434 edl->session->frame_rate);
435 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
436 edl->local_session->get_selectionend() *
437 edl->session->frame_rate);
441 asset.video_data = 0;
447 if(asset.audio_data &&
448 edl->tracks->playable_audio_tracks() &&
449 File::supports_audio(asset.format))
451 asset.audio_data = 1;
452 asset.channels = edl->session->audio_channels;
453 if(asset.format == FILE_MOV) asset.byte_order = 0;
454 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
455 edl->local_session->get_selectionstart() *
456 edl->session->sample_rate);
457 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
458 edl->local_session->get_selectionend() *
459 edl->session->sample_rate);
463 asset.audio_data = 0;
469 if(!asset.audio_data &&
477 int Render::fix_strategy(int strategy, int use_renderfarm)
481 if(strategy == FILE_PER_LABEL)
482 strategy = FILE_PER_LABEL_FARM;
484 if(strategy == SINGLE_PASS)
485 strategy = SINGLE_PASS_FARM;
489 if(strategy == FILE_PER_LABEL_FARM)
490 strategy = FILE_PER_LABEL;
492 if(strategy == SINGLE_PASS_FARM)
493 strategy = SINGLE_PASS;
498 void Render::start_progress()
500 char filename[BCTEXTLEN];
501 char string[BCTEXTLEN];
504 progress_max = Units::to_int64(default_asset->sample_rate *
505 (total_end - total_start)) +
506 Units::to_int64(preferences->render_preroll *
507 packages->total_allocated *
508 default_asset->sample_rate);
509 progress_timer->update();
513 // Generate the progress box
514 fs.extract_name(filename, default_asset->path);
515 sprintf(string, _("Rendering %s..."), filename);
517 // Don't bother with the filename since renderfarm defeats the meaning
518 progress = mwindow->mainprogress->start_progress(_("Rendering..."),
520 render_progress = new RenderProgress(mwindow, this);
521 render_progress->start();
525 void Render::stop_progress()
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();
536 sprintf(string2, _("Rendering took %s"), string);
537 mwindow->gui->lock_window();
538 mwindow->gui->show_message(string2, BLACK);
539 mwindow->gui->unlock_window();
546 int Render::render(int test_overwrite,
551 char string[BCTEXTLEN];
552 // Total length in seconds
554 int last_audio_buffer;
555 RenderFarmServer *farm_server = 0;
557 int total_digits; // Total number of digits including padding the user specified.
558 int number_start; // Character in the filename path at which the number begins
559 int current_number; // The number the being injected into the filename.
561 // (VFrame*)(VFrame array [])(Channel [])
562 VFrame ***video_output;
563 // Pointer to output buffers
564 VFrame *video_output_ptr[MAX_CHANNELS];
565 double *audio_output_ptr[MAX_CHANNELS];
570 this->default_asset = asset;
577 preferences = new Preferences;
579 preferences->copy_from(mwindow->preferences);
583 // Create rendering command
584 command = new TransportCommand;
585 command->command = NORMAL_FWD;
586 command->get_edl()->copy_all(edl);
587 command->change_type = CHANGE_ALL;
588 // Get highlighted playback range
589 command->set_playback_range();
590 // Adjust playback range with in/out points
591 command->adjust_playback_range();
592 packages = new PackageDispatcher;
595 // Configure preview monitor
596 VideoOutConfig vconfig;
597 PlaybackConfig *playback_config = new PlaybackConfig;
598 for(int i = 0; i < MAX_CHANNELS; i++)
600 vconfig.do_channel[i] = (i < command->get_edl()->session->video_channels);
601 playback_config->vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
602 playback_config->aconfig->do_channel[i] = (i < command->get_edl()->session->audio_channels);
606 audio_cache = new CICache(command->get_edl(), preferences, plugindb);
607 video_cache = new CICache(command->get_edl(), preferences, plugindb);
609 default_asset->frame_rate = command->get_edl()->session->frame_rate;
610 default_asset->sample_rate = command->get_edl()->session->sample_rate;
612 // Conform asset to EDL. Find out if any tracks are playable.
613 result = check_asset(command->get_edl(), *default_asset);
617 // Get total range to render
618 total_start = command->start_position;
619 total_end = command->end_position;
620 total_length = total_end - total_start;
623 if(EQUIV(total_length, 0))
638 // Stop background rendering
639 if(mwindow) mwindow->stop_brender();
641 fs.complete_path(default_asset->path);
642 strategy = Render::fix_strategy(strategy, preferences->use_renderfarm);
644 result = packages->create_packages(mwindow,
665 frames_per_second = 0;
669 // Start dispatching external jobs
672 mwindow->gui->lock_window();
673 mwindow->gui->show_message(_("Starting render farm"), BLACK);
674 mwindow->gui->unlock_window();
678 printf("Render::render: starting render farm\n");
681 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
683 farm_server = new RenderFarmServer(plugindb,
693 result = farm_server->start_clients();
699 mwindow->gui->lock_window();
700 mwindow->gui->show_message(_("Failed to start render farm"), BLACK);
701 mwindow->gui->unlock_window();
705 printf("Render::render: Failed to start render farm\n");
714 // Perform local rendering
724 MainPackageRenderer package_renderer(this);
725 result = package_renderer.initialize(mwindow,
726 command->get_edl(), // Copy of master EDL
739 // Get unfinished job
740 RenderPackage *package;
742 if(strategy == SINGLE_PASS_FARM)
744 package = packages->get_package(frames_per_second, -1, 1);
748 package = packages->get_package(0, -1, 1);
763 if(package_renderer.render_package(package))
766 // Result is also set directly by the RenderFarm.
768 frames_per_second = (double)(package->video_end - package->video_start) /
769 (double)(timer.get_difference() / 1000);
776 //printf("Render::run: Session finished.\n");
779 //printf("Render::render 80\n");
783 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
785 farm_server->wait_clients();
788 //printf("Render::render 90\n");
792 (!progress || !progress->is_cancelled()) &&
797 ErrorBox error_box(PROGRAM_NAME ": Error",
798 mwindow->gui->get_abs_cursor_x(1),
799 mwindow->gui->get_abs_cursor_y(1));
800 error_box.create_objects(_("Error rendering data."));
801 error_box.run_window();
805 printf("Render::render: Error rendering data\n");
809 // Delete the progress box
812 //printf("Render::render 100\n");
820 // Paste all packages into timeline if desired
823 load_mode != LOAD_NOTHING &&
825 mode != Render::BATCH)
827 mwindow->gui->lock_window();
830 mwindow->undo->update_undo_before(_("render"), LOAD_ALL);
833 ArrayList<Asset*> *assets = packages->get_asset_list();
834 if(load_mode == LOAD_PASTE)
836 mwindow->load_assets(assets,
841 mwindow->edl->session->labels_follow_edits,
842 mwindow->edl->session->plugins_follow_edits);
843 assets->remove_all_objects();
847 mwindow->save_backup();
848 mwindow->undo->update_undo_after();
849 mwindow->update_plugin_guis();
850 mwindow->gui->update(1,
857 mwindow->sync_parameters(CHANGE_ALL);
858 mwindow->gui->unlock_window();
861 //printf("Render::render 110\n");
862 // Need to restart because brender always stops before render.
864 mwindow->restart_brender();
865 if(farm_server) delete farm_server;
867 delete playback_config;
870 // Must delete packages after server
873 completion->unlock();
874 //printf("Render::render 120\n");
880 void Render::create_filename(char *path,
887 int len = strlen(default_path);
888 char printf_string[BCTEXTLEN];
889 int found_number = 0;
891 for(i = 0, j = 0; i < number_start; i++, j++)
893 printf_string[j] = default_path[i];
897 sprintf(&printf_string[j], "%%0%dd", total_digits);
898 j = strlen(printf_string);
901 // Copy remainder of string
902 for( ; i < len; i++, j++)
904 printf_string[j] = default_path[i];
906 printf_string[j] = 0;
907 // Print the printf argument to the path
908 sprintf(path, printf_string, current_number);
911 void Render::get_starting_number(char *path,
918 int len = strlen(path);
919 char number_text[BCTEXTLEN];
927 ptr2 = strrchr(path, '/');
929 // Search for first 0 after last /.
931 ptr = strchr(ptr2, '0');
933 if(ptr && isdigit(*ptr))
935 number_start = ptr - path;
937 // Store the first number
938 char *ptr2 = number_text;
942 current_number = atol(number_text);
943 total_digits = strlen(number_text);
947 // No number found or number not long enough
948 if(total_digits < min_digits)
952 total_digits = min_digits;
962 int Render::load_defaults(Asset *asset)
964 strategy = mwindow->defaults->get("RENDER_STRATEGY", SINGLE_PASS);
965 load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOAD_NEW_TRACKS);
968 asset->load_defaults(mwindow->defaults,
980 int Render::save_defaults(Asset *asset)
982 mwindow->defaults->update("RENDER_STRATEGY", strategy);
983 mwindow->defaults->update("RENDER_LOADMODE", load_mode);
988 asset->save_defaults(mwindow->defaults,
1006 RenderWindow::RenderWindow(MWindow *mwindow, Render *render, Asset *asset)
1007 : BC_Window(PROGRAM_NAME ": Render",
1008 mwindow->gui->get_root_w(0, 1) / 2 - WIDTH / 2,
1009 mwindow->gui->get_root_h(1) / 2 - HEIGHT / 2,
1018 this->mwindow = mwindow;
1019 this->render = render;
1020 this->asset = asset;
1023 RenderWindow::~RenderWindow()
1025 delete format_tools;
1031 int RenderWindow::create_objects()
1034 add_subwindow(new BC_Title(x,
1036 (char*)((render->strategy == FILE_PER_LABEL ||
1037 render->strategy == FILE_PER_LABEL_FARM) ?
1038 _("Select the first file to render to:") :
1039 _("Select a file to render to:"))));
1042 format_tools = new FormatTools(mwindow,
1045 format_tools->create_objects(x,
1058 loadmode = new LoadMode(mwindow, this, x, y, &render->load_mode, 1);
1059 loadmode->create_objects();
1061 add_subwindow(new BC_OKButton(this));
1062 add_subwindow(new BC_CancelButton(this));