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"
47 #include "transportque.h"
50 #include "videoconfig.h"
52 #include "renderprofiles.h"
59 RenderItem::RenderItem(MWindow *mwindow)
60 : BC_MenuItem(_("Render..."), "Shift+R", 'R')
62 this->mwindow = mwindow;
66 int RenderItem::handle_event()
68 mwindow->render->start_interactive();
81 RenderProgress::RenderProgress(MWindow *mwindow, Render *render)
84 this->mwindow = mwindow;
85 this->render = render;
87 Thread::set_synchronous(1);
90 RenderProgress::~RenderProgress()
97 void RenderProgress::run()
99 Thread::disable_cancel();
102 if(render->total_rendered != last_value)
104 render->progress->update(render->total_rendered);
105 last_value = render->total_rendered;
108 Thread::enable_cancel();
110 Thread::disable_cancel();
123 MainPackageRenderer::MainPackageRenderer(Render *render)
126 this->render = render;
131 MainPackageRenderer::~MainPackageRenderer()
136 int MainPackageRenderer::get_master()
141 int MainPackageRenderer::get_result()
143 return render->result;
146 void MainPackageRenderer::set_result(int value)
149 render->result = value;
152 void MainPackageRenderer::set_progress(int64_t value)
154 render->counter_lock->lock("MainPackageRenderer::set_progress");
155 render->total_rendered += value;
157 // If non interactive, print progress out
158 if(!render->progress)
160 int64_t current_eta = render->progress_timer->get_scaled_difference(1000);
161 if(current_eta - render->last_eta > 1000)
166 if(render->total_rendered)
170 render->progress_max /
171 render->total_rendered -
176 char string[BCTEXTLEN];
177 Units::totext(string,
181 printf("\r%d%% ETA: %s ", (int)(100 *
182 (float)render->total_rendered /
183 render->progress_max),
186 render->last_eta = current_eta;
190 render->counter_lock->unlock();
193 int MainPackageRenderer::progress_cancelled()
195 return (render->progress && render->progress->is_cancelled()) ||
196 render->batch_cancelled;
210 Render::Render(MWindow *mwindow)
213 this->mwindow = mwindow;
214 if(mwindow) plugindb = mwindow->plugindb;
219 package_lock = new Mutex("Render::package_lock");
220 counter_lock = new Mutex("Render::counter_lock");
221 completion = new Condition(0, "Render::completion");
222 progress_timer = new Timer;
223 range_type = RANGE_BACKCOMPAT;
231 if(preferences) delete preferences;
232 delete progress_timer;
235 void Render::start_interactive()
237 if(!Thread::running())
239 mode = Render::INTERACTIVE;
247 // raise the window if rendering hasn't started yet
248 if (render_window && ! in_progress) {
249 render_window->raise_window();
252 ErrorBox error_box(PROGRAM_NAME ": Error",
253 mwindow->gui->get_abs_cursor_x(1),
254 mwindow->gui->get_abs_cursor_y(1));
255 error_box.create_objects("Already rendering");
256 error_box.raise_window();
257 error_box.run_window();
262 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs)
265 if(!Thread::running())
267 mode = Render::BATCH;
274 ErrorBox error_box(PROGRAM_NAME ": Error",
275 mwindow->gui->get_abs_cursor_x(1),
276 mwindow->gui->get_abs_cursor_y(1));
277 error_box.create_objects("Already rendering");
278 error_box.raise_window();
279 error_box.run_window();
283 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs,
284 BC_Hash *boot_defaults,
285 Preferences *preferences,
286 ArrayList<PluginServer*> *plugindb)
288 mode = Render::BATCH;
291 this->preferences = preferences;
292 this->plugindb = plugindb;
296 this->preferences = 0;
299 void Render::stop_operation()
301 if(Thread::running())
304 // Wait for completion
305 completion->lock("Render::stop_operation");
318 if(mode == Render::INTERACTIVE)
320 // Fix the asset for rendering
321 printf("Render::run 1\n");
322 Asset_GC asset = Asset_GC(new Asset);
323 load_defaults(asset);
324 printf("Render::run 2\n");
325 check_asset(mwindow->edl, *asset);
326 printf("Render::run 3\n");
328 // Get format from user
331 printf("Render::run 4\n");
338 printf("Render::run 5\n");
339 RenderWindow window(mwindow, this, asset);
340 printf("Render::run 6\n");
341 window.create_objects();
342 printf("Render::run 7\n");
343 result = window.run_window();
344 printf("Render::run 8\n");
346 // add to recentlist only on OK
347 window.format_tools->path_recent->add_item(FILE_FORMAT_PREFIX(asset->format), asset->path);
353 printf("Render::run 8.1\n");
354 // Check the asset format for errors.
355 FormatCheck format_check(asset);
356 printf("Render::run 8.2\n");
357 format_error = format_check.check_format();
358 printf("Render::run 8.3\n");
360 }while(format_error && !result);
362 printf("Render::run 9\n");
364 save_defaults(asset);
365 mwindow->save_defaults();
366 printf("Render::run 10\n");
368 if(!result) render(1, asset, mwindow->edl, strategy, range_type);
369 printf("Render::run 11\n");
371 printf("Render::run 12\n");
374 if(mode == Render::BATCH)
376 for(int i = 0; i < jobs->total && !result; i++)
378 BatchRenderJob *job = jobs->values[i];
383 mwindow->batch_render->update_active(i);
387 printf("Render::run: %s\n", job->edl_path);
391 FileXML *file = new FileXML;
393 edl->create_objects();
394 file->read_from_file(job->edl_path);
395 if(!plugindb && mwindow)
396 plugindb = mwindow->plugindb;
397 edl->load_xml(plugindb, file, LOAD_ALL);
399 check_asset(edl, *job->asset);
400 render(0, job->asset, edl, job->strategy, RANGE_BACKCOMPAT);
407 mwindow->batch_render->update_done(i, 1, elapsed_time);
410 char string[BCTEXTLEN];
412 (double)progress_timer->get_scaled_difference(1);
413 Units::totext(string,
416 printf("Render::run: done in %s\n", string);
422 mwindow->batch_render->update_active(-1);
424 printf("Render::run: failed\n");
431 mwindow->batch_render->update_active(-1);
432 mwindow->batch_render->update_done(-1, 0, 0);
435 printf("Render::run 100\n");
440 int Render::check_asset(EDL *edl, Asset &asset)
442 if(asset.video_data &&
443 edl->tracks->playable_video_tracks() &&
444 File::supports_video(asset.format))
446 asset.video_data = 1;
448 asset.width = edl->session->output_w;
449 asset.height = edl->session->output_h;
450 asset.interlace_mode = edl->session->interlace_mode;
451 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
452 edl->local_session->get_selectionstart() *
453 edl->session->frame_rate);
454 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
455 edl->local_session->get_selectionend() *
456 edl->session->frame_rate);
460 asset.video_data = 0;
466 if(asset.audio_data &&
467 edl->tracks->playable_audio_tracks() &&
468 File::supports_audio(asset.format))
470 asset.audio_data = 1;
471 asset.channels = edl->session->audio_channels;
472 if(asset.format == FILE_MOV) asset.byte_order = 0;
473 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
474 edl->local_session->get_selectionstart() *
475 edl->session->sample_rate);
476 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
477 edl->local_session->get_selectionend() *
478 edl->session->sample_rate);
482 asset.audio_data = 0;
488 if(!asset.audio_data &&
496 int Render::fix_strategy(int strategy, int use_renderfarm)
500 if(strategy == FILE_PER_LABEL)
501 strategy = FILE_PER_LABEL_FARM;
503 if(strategy == SINGLE_PASS)
504 strategy = SINGLE_PASS_FARM;
508 if(strategy == FILE_PER_LABEL_FARM)
509 strategy = FILE_PER_LABEL;
511 if(strategy == SINGLE_PASS_FARM)
512 strategy = SINGLE_PASS;
517 void Render::start_progress()
519 char filename[BCTEXTLEN];
520 char string[BCTEXTLEN];
523 progress_max = packages->get_progress_max();
525 progress_timer->update();
529 // Generate the progress box
530 fs.extract_name(filename, default_asset->path);
531 sprintf(string, _("Rendering %s..."), filename);
533 // Don't bother with the filename since renderfarm defeats the meaning
534 progress = mwindow->mainprogress->start_progress(_("Rendering..."),
536 render_progress = new RenderProgress(mwindow, this);
537 render_progress->start();
541 void Render::stop_progress()
545 char string[BCTEXTLEN], string2[BCTEXTLEN];
546 delete render_progress;
547 progress->get_time(string);
548 elapsed_time = progress->get_time();
549 progress->stop_progress();
552 sprintf(string2, _("Rendering took %s"), string);
553 mwindow->gui->lock_window("");
554 mwindow->gui->show_message(string2);
555 mwindow->gui->stop_hourglass();
556 mwindow->gui->unlock_window();
563 int Render::render(int test_overwrite,
569 char string[BCTEXTLEN];
570 // Total length in seconds
572 int last_audio_buffer;
573 RenderFarmServer *farm_server = 0;
575 int total_digits; // Total number of digits including padding the user specified.
576 int number_start; // Character in the filename path at which the number begins
577 int current_number; // The number the being injected into the filename.
579 // (VFrame*)(VFrame array [])(Channel [])
580 VFrame ***video_output;
581 // Pointer to output buffers
582 VFrame *video_output_ptr[MAX_CHANNELS];
583 double *audio_output_ptr[MAX_CHANNELS];
588 this->default_asset = asset;
595 preferences = new Preferences;
597 preferences->copy_from(mwindow->preferences);
601 // Create rendering command
602 command = new TransportCommand;
603 command->command = NORMAL_FWD;
604 command->get_edl()->copy_all(edl);
605 command->change_type = CHANGE_ALL;
606 if (range_type == RANGE_BACKCOMPAT)
608 // Get highlighted playback range
609 command->set_playback_range();
610 // Adjust playback range with in/out points
611 command->playback_range_adjust_inout();
613 if (range_type == RANGE_PROJECT)
615 command->playback_range_project();
617 if (range_type == RANGE_SELECTION)
619 command->set_playback_range();
621 if (range_type == RANGE_INOUT)
623 command->playback_range_inout();
625 packages = new PackageDispatcher;
628 // Configure preview monitor
629 VideoOutConfig vconfig;
630 PlaybackConfig *playback_config = new PlaybackConfig;
633 audio_cache = new CICache(preferences, plugindb);
634 video_cache = new CICache(preferences, plugindb);
636 default_asset->frame_rate = command->get_edl()->session->frame_rate;
637 default_asset->sample_rate = command->get_edl()->session->sample_rate;
639 // Conform asset to EDL. Find out if any tracks are playable.
640 result = check_asset(command->get_edl(), *default_asset);
644 // Get total range to render
645 total_start = command->start_position;
646 total_end = command->end_position;
647 total_length = total_end - total_start;
650 if(EQUIV(total_length, 0))
665 // Stop background rendering
666 if(mwindow) mwindow->stop_brender();
668 fs.complete_path(default_asset->path);
669 strategy = Render::fix_strategy(strategy, preferences->use_renderfarm);
671 result = packages->create_packages(mwindow,
692 frames_per_second = 0;
696 // Start dispatching external jobs
699 mwindow->gui->lock_window("Render::render 1");
700 mwindow->gui->show_message(_("Starting render farm"));
701 mwindow->gui->start_hourglass();
702 mwindow->gui->unlock_window();
706 printf("Render::render: starting render farm\n");
709 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
711 farm_server = new RenderFarmServer(plugindb,
721 result = farm_server->start_clients();
727 mwindow->gui->lock_window("Render::render 2");
728 mwindow->gui->show_message(_("Failed to start render farm"),
729 mwindow->theme->message_error);
730 mwindow->gui->stop_hourglass();
731 mwindow->gui->unlock_window();
735 printf("Render::render: Failed to start render farm\n");
744 // Perform local rendering
754 MainPackageRenderer package_renderer(this);
755 result = package_renderer.initialize(mwindow,
756 command->get_edl(), // Copy of master EDL
769 // Get unfinished job
770 RenderPackage *package;
772 if(strategy == SINGLE_PASS_FARM)
774 package = packages->get_package(frames_per_second, -1, 1);
778 package = packages->get_package(0, -1, 1);
793 if(package_renderer.render_package(package))
796 // Result is also set directly by the RenderFarm.
798 frames_per_second = (double)(package->video_end - package->video_start) /
799 (double)(timer.get_difference() / 1000);
806 printf("Render::run: Session finished.\n");
812 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
814 farm_server->wait_clients();
815 result |= packages->packages_are_done();
818 printf("Render::render 90\n");
822 (!progress || !progress->is_cancelled()) &&
827 ErrorBox error_box(PROGRAM_NAME ": Error",
828 mwindow->gui->get_abs_cursor_x(1),
829 mwindow->gui->get_abs_cursor_y(1));
830 error_box.create_objects(_("Error rendering data."));
831 error_box.raise_window();
832 error_box.run_window();
836 printf("Render::render: Error rendering data\n");
840 // Delete the progress box
843 //printf("Render::render 100\n");
851 // Paste all packages into timeline if desired
854 load_mode != LOAD_NOTHING &&
856 mode != Render::BATCH)
858 mwindow->gui->lock_window("Render::render 3");
863 Assets_vector assets;
864 packages->get_asset_list(assets);
866 if(load_mode == LOAD_PASTE)
868 mwindow->load_assets(assets,
873 mwindow->edl->session->labels_follow_edits,
874 mwindow->edl->session->plugins_follow_edits,
878 mwindow->save_backup();
879 mwindow->undo->update_undo(_("render"), LOAD_ALL);
880 mwindow->update_plugin_guis();
881 mwindow->gui->update(1,
888 mwindow->sync_parameters(CHANGE_ALL);
889 mwindow->gui->unlock_window();
896 mwindow->gui->lock_window("Render::render 3");
897 mwindow->gui->stop_hourglass();
898 mwindow->gui->unlock_window();
901 //printf("Render::render 110\n");
902 // Need to restart because brender always stops before render.
904 mwindow->restart_brender();
905 if(farm_server) delete farm_server;
907 delete playback_config;
910 // Must delete packages after server
913 completion->unlock();
914 //printf("Render::render 120\n");
920 void Render::create_filename(char *path,
927 int len = strlen(default_path);
928 char printf_string[BCTEXTLEN];
929 int found_number = 0;
931 for(i = 0, j = 0; i < number_start; i++, j++)
933 printf_string[j] = default_path[i];
937 sprintf(&printf_string[j], "%%0%dd", total_digits);
938 j = strlen(printf_string);
941 // Copy remainder of string
942 for( ; i < len; i++, j++)
944 printf_string[j] = default_path[i];
946 printf_string[j] = 0;
947 // Print the printf argument to the path
948 sprintf(path, printf_string, current_number);
951 void Render::get_starting_number(char *path,
958 int len = strlen(path);
959 char number_text[BCTEXTLEN];
967 ptr2 = strrchr(path, '/');
969 // Search for first 0 after last /.
971 ptr = strchr(ptr2, '0');
973 if(ptr && isdigit(*ptr))
975 number_start = ptr - path;
977 // Store the first number
978 char *ptr2 = number_text;
982 current_number = atol(number_text);
983 total_digits = strlen(number_text);
987 // No number found or number not long enough
988 if(total_digits < min_digits)
992 total_digits = min_digits;
1002 int Render::load_defaults(Asset_GC asset)
1004 strategy = mwindow->defaults->get("RENDER_STRATEGY", SINGLE_PASS);
1005 load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOAD_NEW_TRACKS);
1006 range_type = mwindow->defaults->get("RENDER_RANGE_TYPE", RANGE_PROJECT);
1009 asset->load_defaults(mwindow->defaults,
1021 int Render::load_profile(int profile_slot, Asset_GC asset)
1023 char string_name[100];
1024 sprintf(string_name, "RENDER_%i_STRATEGY", profile_slot);
1025 strategy = mwindow->defaults->get(string_name, SINGLE_PASS);
1026 // Load mode is not part of the profile
1027 // printf(string_name, "RENDER_%i_LOADMODE", profile_slot);
1028 // load_mode = mwindow->defaults->get(string_name, LOAD_NEW_TRACKS);
1029 sprintf(string_name, "RENDER_%i_RANGE_TYPE", profile_slot);
1030 range_type = mwindow->defaults->get(string_name, RANGE_PROJECT);
1033 sprintf(string_name, "RENDER_%i_", profile_slot);
1034 asset->load_defaults(mwindow->defaults,
1048 int Render::save_defaults(Asset_GC asset)
1050 mwindow->defaults->update("RENDER_STRATEGY", strategy);
1051 mwindow->defaults->update("RENDER_LOADMODE", load_mode);
1052 mwindow->defaults->update("RENDER_RANGE_TYPE", range_type);
1057 asset->save_defaults(mwindow->defaults,
1075 RenderWindow::RenderWindow(MWindow *mwindow, Render *render, Asset_GC asset)
1076 : BC_Window(PROGRAM_NAME ": Render",
1077 mwindow->gui->get_root_w(0, 1) / 2 - WIDTH / 2,
1078 mwindow->gui->get_root_h(1) / 2 - HEIGHT / 2,
1087 this->mwindow = mwindow;
1088 this->render = render;
1089 this->asset = asset;
1092 RenderWindow::~RenderWindow()
1094 delete format_tools;
1099 int RenderWindow::load_profile(int profile_slot)
1101 render->load_profile(profile_slot, asset);
1102 update_range_type(render->range_type);
1103 format_tools->update(asset, &render->strategy);
1108 int RenderWindow::create_objects()
1111 add_subwindow(new BC_Title(x,
1113 (char*)((render->strategy == FILE_PER_LABEL ||
1114 render->strategy == FILE_PER_LABEL_FARM) ?
1115 _("Select the first file to render to:") :
1116 _("Select a file to render to:"))));
1119 format_tools = new FormatTools(mwindow,
1122 format_tools->create_objects(x,
1134 add_subwindow(new BC_Title(x,
1136 _("Render range:")));
1139 add_subwindow(rangeproject = new RenderRangeProject(this,
1140 render->range_type == RANGE_PROJECT,
1144 add_subwindow(rangeselection = new RenderRangeSelection(this,
1145 render->range_type == RANGE_SELECTION,
1149 add_subwindow(rangeinout = new RenderRangeInOut(this,
1150 render->range_type == RANGE_INOUT,
1156 renderprofile = new RenderProfile(mwindow, this, x, y, 1);
1157 renderprofile->create_objects();
1159 loadmode = new LoadMode(mwindow, this, x, y, &render->load_mode, 1);
1160 loadmode->create_objects();
1164 add_subwindow(new BC_OKButton(this));
1165 add_subwindow(new BC_CancelButton(this));
1170 void RenderWindow::update_range_type(int range_type)
1172 render->range_type = range_type;
1173 rangeproject->update(range_type == RANGE_PROJECT);
1174 rangeselection->update(range_type == RANGE_SELECTION);
1175 rangeinout->update(range_type == RANGE_INOUT);
1179 RenderRangeProject::RenderRangeProject(RenderWindow *rwindow, int value, int x, int y)
1180 : BC_Radial(x, y, value, _("Project"))
1182 this->rwindow = rwindow;
1184 int RenderRangeProject::handle_event()
1186 rwindow->update_range_type(RANGE_PROJECT);
1190 RenderRangeSelection::RenderRangeSelection(RenderWindow *rwindow, int value, int x, int y)
1191 : BC_Radial(x, y, value, _("Selection"))
1193 this->rwindow = rwindow;
1195 int RenderRangeSelection::handle_event()
1197 rwindow->update_range_type(RANGE_SELECTION);
1202 RenderRangeInOut::RenderRangeInOut(RenderWindow *rwindow, int value, int x, int y)
1203 : BC_Radial(x, y, value, _("In/Out Points"))
1205 this->rwindow = rwindow;
1207 int RenderRangeInOut::handle_event()
1209 rwindow->update_range_type(RANGE_INOUT);
1217 // c-file-style: "linux"