4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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.
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.
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
26 #include "awindowgui.h"
27 #include "batchrender.h"
28 #include "bcprogressbox.h"
29 #include "bcsignals.h"
32 #include "compresspopup.h"
33 #include "condition.h"
34 #include "confirmsave.h"
35 #include "cwindowgui.h"
40 #include "edlsession.h"
43 #include "filesystem.h"
45 #include "formatcheck.h"
46 #include "formatpopup.h"
47 #include "formattools.h"
48 #include "indexable.h"
52 #include "localsession.h"
53 #include "mainprogress.h"
54 #include "mainsession.h"
58 #include "mwindowgui.h"
60 #include "packagedispatcher.h"
61 #include "packagerenderer.h"
63 #include "playabletracks.h"
64 #include "preferences.h"
65 #include "preferencesthread.h"
66 #include "renderfarm.h"
68 #include "statusbar.h"
72 #include "transportque.h"
75 #include "videoconfig.h"
83 RenderItem::RenderItem(MWindow *mwindow)
84 : BC_MenuItem(_("Render..."), _("Shift+R"), 'R')
86 this->mwindow = mwindow;
90 int RenderItem::handle_event()
92 mwindow->gui->unlock_window();
93 mwindow->render->start_interactive();
94 mwindow->gui->lock_window("RenderItem::handle_event");
107 RenderProgress::RenderProgress(MWindow *mwindow, Render *render)
110 this->mwindow = mwindow;
111 this->render = render;
113 Thread::set_synchronous(1);
116 RenderProgress::~RenderProgress()
123 void RenderProgress::run()
125 Thread::disable_cancel();
128 if(render->total_rendered != last_value)
130 render->progress->update(render->total_rendered);
131 last_value = render->total_rendered;
133 if(mwindow) mwindow->preferences_thread->update_rates();
136 Thread::enable_cancel();
138 Thread::disable_cancel();
151 MainPackageRenderer::MainPackageRenderer(Render *render)
154 this->render = render;
159 MainPackageRenderer::~MainPackageRenderer()
164 int MainPackageRenderer::get_master()
169 int MainPackageRenderer::get_result()
171 return render->result;
174 void MainPackageRenderer::set_result(int value)
177 render->result = value;
183 void MainPackageRenderer::set_progress(int64_t value)
185 render->counter_lock->lock("MainPackageRenderer::set_progress");
186 // Increase total rendered for all nodes
187 render->total_rendered += value;
189 // Update frames per second for master node
190 render->preferences->set_rate(frames_per_second, -1);
192 //printf("MainPackageRenderer::set_progress %d %ld %f\n", __LINE__, (long)value, frames_per_second);
194 // If non interactive, print progress out
195 if(!render->progress)
197 int64_t current_eta = render->progress_timer->get_scaled_difference(1000);
198 if(current_eta - render->last_eta > 1000)
203 if(render->total_rendered)
207 render->progress_max /
208 render->total_rendered -
213 char string[BCTEXTLEN];
214 Units::totext(string,
218 printf(_("\r%d%% ETA: %s "), (int)(100 *
219 (float)render->total_rendered /
220 render->progress_max),
223 render->last_eta = current_eta;
227 render->counter_lock->unlock();
229 // This locks the preferences
230 if(mwindow) mwindow->preferences->copy_rates_from(preferences);
233 int MainPackageRenderer::progress_cancelled()
235 return (render->progress && render->progress->is_cancelled()) ||
236 render->batch_cancelled;
250 Render::Render(MWindow *mwindow)
253 this->mwindow = mwindow;
258 package_lock = new Mutex("Render::package_lock");
259 counter_lock = new Mutex("Render::counter_lock");
260 completion = new Condition(0, "Render::completion");
261 progress_timer = new Timer;
262 thread = new RenderThread(mwindow, this);
273 // May be owned by someone else. This is owned by mwindow, so we don't care
275 // delete preferences;
276 delete progress_timer;
277 if( asset ) asset->Garbage::remove_user();
281 void Render::start_interactive()
283 if(!thread->running())
285 mode = Render::INTERACTIVE;
286 BC_DialogThread::start();
290 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
291 mwindow->gui->get_abs_cursor_x(1),
292 mwindow->gui->get_abs_cursor_y(1));
293 error_box.create_objects(_("Already rendering"));
294 error_box.raise_window();
295 error_box.run_window();
300 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs)
302 if(!thread->running())
304 mode = Render::BATCH;
312 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs,
313 BC_Hash *boot_defaults,
314 Preferences *preferences)
316 mode = Render::BATCH;
319 this->preferences = preferences;
325 this->preferences = 0;
329 BC_Window* Render::new_gui()
336 RenderWindow *window = 0;
338 if(mode == Render::INTERACTIVE)
340 // Fix the asset for rendering
341 if(!asset) asset = new Asset;
342 load_defaults(asset);
343 check_asset(mwindow->edl, *asset);
345 // Get format from user
346 window = new RenderWindow(mwindow,
349 mwindow->gui->get_abs_cursor_x(1),
350 mwindow->gui->get_abs_cursor_y(1));
351 window->create_objects();
362 void Render::handle_close_event(int result)
364 int format_error = 0;
369 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
370 // Check the asset format for errors.
371 FormatCheck format_check(asset);
372 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
373 format_error = format_check.check_format();
374 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
379 save_defaults(asset);
381 mwindow->save_defaults();
384 if(!format_error && !result)
386 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
387 if(!result) start_render();
388 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
395 void Render::stop_operation()
397 if(thread->Thread::running())
400 // Wait for completion
401 completion->lock("Render::stop_operation");
409 int Render::check_asset(EDL *edl, Asset &asset)
411 if(asset.video_data &&
412 edl->tracks->playable_video_tracks() &&
413 File::supports_video(asset.format))
415 asset.video_data = 1;
417 asset.width = edl->session->output_w;
418 asset.height = edl->session->output_h;
422 asset.video_data = 0;
426 if(asset.audio_data &&
427 edl->tracks->playable_audio_tracks() &&
428 File::supports_audio(asset.format))
430 asset.audio_data = 1;
431 asset.channels = edl->session->audio_channels;
435 asset.audio_data = 0;
439 if(!asset.audio_data &&
447 int Render::fix_strategy(int strategy, int use_renderfarm)
451 if(strategy == FILE_PER_LABEL)
452 strategy = FILE_PER_LABEL_FARM;
454 if(strategy == SINGLE_PASS)
455 strategy = SINGLE_PASS_FARM;
459 if(strategy == FILE_PER_LABEL_FARM)
460 strategy = FILE_PER_LABEL;
462 if(strategy == SINGLE_PASS_FARM)
463 strategy = SINGLE_PASS;
468 void Render::start_progress()
470 char filename[BCTEXTLEN];
471 char string[BCTEXTLEN];
474 progress_max = Units::to_int64(default_asset->sample_rate *
475 (total_end - total_start)) +
476 Units::to_int64(preferences->render_preroll *
477 packages->total_allocated *
478 default_asset->sample_rate);
479 progress_timer->update();
483 // Generate the progress box
484 fs.extract_name(filename, default_asset->path);
485 sprintf(string, _("Rendering %s..."), filename);
487 // Don't bother with the filename since renderfarm defeats the meaning
488 progress = mwindow->mainprogress->start_progress(_("Rendering..."),
490 render_progress = new RenderProgress(mwindow, this);
491 render_progress->start();
495 void Render::stop_progress()
499 char string[BCTEXTLEN], string2[BCTEXTLEN];
500 delete render_progress;
501 progress->get_time(string);
502 elapsed_time = progress->get_time();
503 progress->stop_progress();
506 sprintf(string2, _("Rendering took %s"), string);
507 mwindow->gui->lock_window("");
508 mwindow->gui->show_message(string2);
509 mwindow->gui->stop_hourglass();
510 mwindow->gui->unlock_window();
517 void Render::start_render()
526 void Render::create_filename(char *path,
533 int len = strlen(default_path);
534 char printf_string[BCTEXTLEN];
536 for(i = 0, j = 0; i < number_start; i++, j++)
538 printf_string[j] = default_path[i];
542 sprintf(&printf_string[j], "%%0%dd", total_digits);
543 j = strlen(printf_string);
546 // Copy remainder of string
547 for( ; i < len; i++, j++)
549 printf_string[j] = default_path[i];
551 printf_string[j] = 0;
552 // Print the printf argument to the path
553 sprintf(path, printf_string, current_number);
556 void Render::get_starting_number(char *path,
562 int len = strlen(path);
563 char number_text[BCTEXTLEN];
571 ptr2 = strrchr(path, '/');
573 // Search for first 0 after last /.
575 ptr = strchr(ptr2, '0');
577 if(ptr && isdigit(*ptr))
579 number_start = ptr - path;
581 // Store the first number
582 char *ptr2 = number_text;
586 current_number = atol(number_text);
587 total_digits = strlen(number_text);
591 // No number found or number not long enough
592 if(total_digits < min_digits)
596 total_digits = min_digits;
606 int Render::load_defaults(Asset *asset)
608 strategy = mwindow->defaults->get("RENDER_STRATEGY", SINGLE_PASS);
609 load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOADMODE_NEW_TRACKS);
611 // some defaults which work
612 asset->video_data = 1;
613 asset->audio_data = 1;
614 asset->format = FILE_FFMPEG;
615 strcpy(asset->acodec, "mp4.qt");
616 strcpy(asset->vcodec, "mp4.qt");
618 asset->load_defaults(mwindow->defaults,
619 "RENDER_", 1, 1, 1, 1, 1);
624 int Render::save_defaults(Asset *asset)
626 mwindow->defaults->update("RENDER_STRATEGY", strategy);
627 mwindow->defaults->update("RENDER_LOADMODE", load_mode);
632 asset->save_defaults(mwindow->defaults,
648 static void run_script(const char *script, const char *arg)
650 char *const argv[] = { (char*)script, (char*)arg, 0 };
651 execvp(script ,&argv[0]);
652 perror("execvp script failed");
656 RenderThread::RenderThread(MWindow *mwindow, Render *render)
659 this->mwindow = mwindow;
660 this->render = render;
663 RenderThread::~RenderThread()
668 void RenderThread::render_single(int test_overwrite,
673 // Total length in seconds
675 RenderFarmServer *farm_server = 0;
680 render->in_progress = 1;
683 render->default_asset = asset;
684 render->progress = 0;
689 if(!render->preferences)
690 render->preferences = new Preferences;
692 render->preferences->copy_from(mwindow->preferences);
696 // Create rendering command
697 TransportCommand *command = new TransportCommand;
698 command->command = NORMAL_FWD;
699 command->get_edl()->copy_all(edl);
700 command->change_type = CHANGE_ALL;
701 // Get highlighted playback range
702 command->set_playback_range();
703 // Adjust playback range with in/out points
704 command->adjust_playback_range();
705 render->packages = new PackageDispatcher;
708 CICache *audio_cache = new CICache(render->preferences);
709 CICache *video_cache = new CICache(render->preferences);
711 render->default_asset->frame_rate = command->get_edl()->session->frame_rate;
712 render->default_asset->sample_rate = command->get_edl()->session->sample_rate;
714 // Conform asset to EDL. Find out if any tracks are playable.
715 render->result = render->check_asset(command->get_edl(),
716 *render->default_asset);
720 // Get total range to render
721 render->total_start = command->start_position;
722 render->total_end = command->end_position;
723 total_length = render->total_end - render->total_start;
726 if(EQUIV(total_length, 0))
741 // Stop background rendering
742 if(mwindow) mwindow->stop_brender();
744 fs.complete_path(render->default_asset->path);
745 strategy = Render::fix_strategy(strategy, render->preferences->use_renderfarm);
747 render->result = render->packages->create_packages(mwindow,
751 render->default_asset,
767 render->total_rendered = 0;
771 // Start dispatching external jobs
774 mwindow->gui->lock_window("Render::render 1");
775 mwindow->gui->show_message(_("Starting render farm"));
776 mwindow->gui->start_hourglass();
777 mwindow->gui->unlock_window();
781 printf("Render::render: starting render farm\n");
784 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
786 farm_server = new RenderFarmServer(mwindow,
791 &render->total_rendered,
792 render->counter_lock,
793 render->default_asset,
796 render->result = farm_server->start_clients();
802 mwindow->gui->lock_window("Render::render 2");
803 mwindow->gui->show_message(_("Failed to start render farm"),
804 mwindow->theme->message_error);
805 mwindow->gui->stop_hourglass();
806 mwindow->gui->unlock_window();
810 printf("Render::render: Failed to start render farm\n");
819 // Perform local rendering
824 render->start_progress();
829 MainPackageRenderer package_renderer(render);
830 render->result = package_renderer.initialize(mwindow,
831 command->get_edl(), // Copy of master EDL
833 render->default_asset);
841 while(!render->result)
843 // Get unfinished job
844 RenderPackage *package;
846 if(strategy == SINGLE_PASS_FARM)
848 package = render->packages->get_package(
849 package_renderer.frames_per_second,
855 package = render->packages->get_package(0, -1, 1);
870 if(package_renderer.render_package(package))
878 printf("Render::render_single: Session finished.\n");
884 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
886 farm_server->wait_clients();
889 if(debug) printf("Render::render %d\n", __LINE__);
893 (!render->progress || !render->progress->is_cancelled()) &&
894 !render->batch_cancelled)
896 if(debug) printf("Render::render %d\n", __LINE__);
899 if(debug) printf("Render::render %d\n", __LINE__);
900 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
901 mwindow->gui->get_abs_cursor_x(1),
902 mwindow->gui->get_abs_cursor_y(1));
903 error_box.create_objects(_("Error rendering data."));
904 error_box.raise_window();
905 error_box.run_window();
906 if(debug) printf("Render::render %d\n", __LINE__);
910 printf("Render::render: Error rendering data\n");
913 if(debug) printf("Render::render %d\n", __LINE__);
915 // Delete the progress box
916 render->stop_progress();
918 if(debug) printf("Render::render %d\n", __LINE__);
926 // Paste all packages into timeline if desired
928 if(!render->result &&
929 render->load_mode != LOADMODE_NOTHING &&
931 render->mode != Render::BATCH)
933 if(debug) printf("Render::render %d\n", __LINE__);
934 mwindow->gui->lock_window("Render::render 3");
935 if(debug) printf("Render::render %d\n", __LINE__);
937 mwindow->undo->update_undo_before();
939 if(debug) printf("Render::render %d\n", __LINE__);
942 ArrayList<Indexable*> *assets = render->packages->get_asset_list();
943 if(debug) printf("Render::render %d\n", __LINE__);
944 if(render->load_mode == LOADMODE_PASTE)
946 if(debug) printf("Render::render %d\n", __LINE__);
947 mwindow->load_assets(assets,
952 mwindow->edl->session->labels_follow_edits,
953 mwindow->edl->session->plugins_follow_edits,
954 mwindow->edl->session->autos_follow_edits);
955 if(debug) printf("Render::render %d\n", __LINE__);
956 for(int i = 0; i < assets->size(); i++)
957 assets->get(i)->Garbage::remove_user();
959 if(debug) printf("Render::render %d\n", __LINE__);
962 mwindow->save_backup();
963 if(debug) printf("Render::render %d\n", __LINE__);
964 mwindow->undo->update_undo_after(_("render"), LOAD_ALL);
965 if(debug) printf("Render::render %d\n", __LINE__);
966 mwindow->update_plugin_guis();
967 if(debug) printf("Render::render %d\n", __LINE__);
968 mwindow->gui->update(1,
975 if(debug) printf("Render::render %d\n", __LINE__);
976 mwindow->sync_parameters(CHANGE_ALL);
977 if(debug) printf("Render::render %d\n", __LINE__);
978 mwindow->gui->unlock_window();
981 mwindow->awindow->gui->lock_window("Render::render");
982 mwindow->awindow->gui->update_assets();
983 mwindow->awindow->gui->flush();
984 mwindow->awindow->gui->unlock_window();
986 if(debug) printf("Render::render %d\n", __LINE__);
989 if(debug) printf("Render::render %d\n", __LINE__);
994 mwindow->gui->lock_window("Render::render 3");
995 mwindow->gui->stop_hourglass();
996 mwindow->gui->unlock_window();
999 //printf("Render::render 110\n");
1000 // Need to restart because brender always stops before render.
1002 mwindow->restart_brender();
1003 if(farm_server) delete farm_server;
1007 // Must delete packages after server
1008 delete render->packages;
1010 render->packages = 0;
1011 render->in_progress = 0;
1012 render->completion->unlock();
1013 if(debug) printf("Render::render %d\n", __LINE__);
1016 void RenderThread::run()
1018 if(render->mode == Render::INTERACTIVE)
1020 render_single(1, render->asset, mwindow->edl, render->strategy);
1023 if(render->mode == Render::BATCH)
1026 // printf("RenderThread::run %d %d %d\n",
1028 // render->jobs->total,
1030 for(int i = 0; i < render->jobs->total && !render->result; i++)
1033 BatchRenderJob *job = render->jobs->values[i];
1037 if( *job->edl_path == '@' )
1039 run_script(job->edl_path+1, job->asset->path);
1044 mwindow->batch_render->update_active(i);
1048 printf("Render::run: %s\n", job->edl_path);
1053 FileXML *file = new FileXML;
1055 edl->create_objects();
1056 file->read_from_file(job->edl_path);
1057 edl->load_xml(file, LOAD_ALL);
1060 render_single(0, job->asset, edl, job->strategy);
1063 edl->Garbage::remove_user();
1068 mwindow->batch_render->update_done(i, 1, render->elapsed_time);
1071 char string[BCTEXTLEN];
1072 render->elapsed_time =
1073 (double)render->progress_timer->get_scaled_difference(1);
1074 Units::totext(string,
1075 render->elapsed_time,
1077 printf("Render::run: done in %s\n", string);
1083 mwindow->batch_render->update_active(-1);
1085 printf("Render::run: failed\n");
1093 mwindow->batch_render->update_active(-1);
1094 mwindow->batch_render->update_done(-1, 0, 0);
1111 RenderWindow::RenderWindow(MWindow *mwindow,
1116 : BC_Window(_(PROGRAM_NAME ": Render"),
1127 this->mwindow = mwindow;
1128 this->render = render;
1129 this->asset = asset;
1132 RenderWindow::~RenderWindow()
1135 lock_window("RenderWindow::~RenderWindow");
1137 delete format_tools;
1147 void RenderWindow::create_objects()
1150 lock_window("RenderWindow::create_objects");
1151 add_subwindow(new BC_Title(x,
1153 (char*)((render->strategy == FILE_PER_LABEL ||
1154 render->strategy == FILE_PER_LABEL_FARM) ?
1155 _("Select the first file to render to:") :
1156 _("Select a file to render to:"))));
1159 format_tools = new FormatTools(mwindow,
1162 format_tools->create_objects(x,
1175 loadmode = new LoadMode(mwindow,
1182 loadmode->create_objects();
1184 add_subwindow(new BC_OKButton(this));
1185 add_subwindow(new BC_CancelButton(this));