4 * Copyright (C) 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
23 #include "batchrender.h"
24 #include "bcdisplayinfo.h"
25 #include "bcsignals.h"
26 #include "confirmsave.h"
32 #include "edlsession.h"
34 #include "filesystem.h"
41 #include "mainerror.h"
43 #include "mainsession.h"
45 #include "mwindowgui.h"
46 #include "packagedispatcher.h"
47 #include "packagerenderer.h"
49 #include "pluginset.h"
50 #include "preferences.h"
54 #include "transportque.h"
58 static const char *list_titles[] =
66 static int list_widths[] =
74 BatchRenderMenuItem::BatchRenderMenuItem(MWindow *mwindow)
75 : BC_MenuItem(_("Batch Render..."), _("Shift-B"), 'B')
78 this->mwindow = mwindow;
81 int BatchRenderMenuItem::handle_event()
83 mwindow->batch_render->start();
94 BatchRenderJob::BatchRenderJob(Preferences *preferences)
96 this->preferences = preferences;
104 BatchRenderJob::~BatchRenderJob()
106 asset->Garbage::remove_user();
109 void BatchRenderJob::copy_from(BatchRenderJob *src)
111 asset->copy_from(src->asset, 0);
112 strcpy(edl_path, src->edl_path);
113 strategy = src->strategy;
114 enabled = src->enabled;
118 void BatchRenderJob::load(FileXML *file)
123 file->tag.get_property("EDL_PATH", edl_path);
124 strategy = file->tag.get_property("STRATEGY", strategy);
125 enabled = file->tag.get_property("ENABLED", enabled);
126 elapsed = file->tag.get_property("ELAPSED", elapsed);
129 result = file->read_tag();
132 if(file->tag.title_is("ASSET"))
134 file->tag.get_property("SRC", asset->path);
135 asset->read(file, 0);
136 // The compression parameters are stored in the defaults to reduce
137 // coding maintenance. The defaults must now be stuffed into the XML for
140 defaults.load_string(file->read_text());
141 asset->load_defaults(&defaults,
152 void BatchRenderJob::save(FileXML *file)
154 file->tag.set_property("EDL_PATH", edl_path);
155 file->tag.set_property("STRATEGY", strategy);
156 file->tag.set_property("ENABLED", enabled);
157 file->tag.set_property("ELAPSED", elapsed);
159 file->append_newline();
164 // The compression parameters are stored in the defaults to reduce
165 // coding maintenance. The defaults must now be stuffed into the XML for
168 asset->save_defaults(&defaults,
176 defaults.save_string(string);
177 file->append_text(string);
179 file->tag.set_title("/JOB");
181 file->append_newline();
184 void BatchRenderJob::fix_strategy()
186 strategy = Render::fix_strategy(strategy, preferences->use_renderfarm);
198 BatchRenderThread::BatchRenderThread(MWindow *mwindow)
201 this->mwindow = mwindow;
209 BatchRenderThread::BatchRenderThread()
220 BatchRenderThread::~BatchRenderThread()
225 void BatchRenderThread::handle_close_event(int result)
228 char path[BCTEXTLEN];
231 save_defaults(mwindow->defaults);
234 jobs.remove_all_objects();
237 file_entries->remove_all_objects();
243 BC_Window* BatchRenderThread::new_gui()
247 default_job = new BatchRenderJob(mwindow->preferences);
252 file_entries = new ArrayList<BC_ListBoxItem*>;
254 char string[BCTEXTLEN];
255 // Load current directory
256 fs.update(getcwd(string, BCTEXTLEN));
257 for(int i = 0; i < fs.total_files(); i++)
259 file_entries->append(
261 fs.get_entry(i)->get_name()));
265 char path[BCTEXTLEN];
267 load_jobs(path, mwindow->preferences);
268 load_defaults(mwindow->defaults);
269 this->gui = new BatchRenderGUI(mwindow,
271 mwindow->session->batchrender_x,
272 mwindow->session->batchrender_y,
273 mwindow->session->batchrender_w,
274 mwindow->session->batchrender_h);
275 this->gui->create_objects();
280 void BatchRenderThread::load_jobs(char *path, Preferences *preferences)
285 jobs.remove_all_objects();
287 file.read_from_file(path);
289 file.read_from_file(create_path(path));
293 if(!(result = file.read_tag()))
295 if(file.tag.title_is("JOB"))
298 jobs.append(job = new BatchRenderJob(preferences));
305 void BatchRenderThread::save_jobs(char *path)
309 for(int i = 0; i < jobs.total; i++)
311 file.tag.set_title("JOB");
312 jobs.values[i]->save(&file);
316 file.write_to_file(path);
318 file.write_to_file(create_path(path));
321 void BatchRenderThread::load_defaults(BC_Hash *defaults)
325 default_job->asset->load_defaults(defaults,
332 default_job->fix_strategy();
335 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
337 char string[BCTEXTLEN];
338 sprintf(string, "BATCHRENDER_COLUMN%d", i);
339 column_width[i] = defaults->get(string, list_widths[i]);
343 void BatchRenderThread::save_defaults(BC_Hash *defaults)
347 default_job->asset->save_defaults(defaults,
354 defaults->update("BATCHRENDER_STRATEGY", default_job->strategy);
356 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
358 char string[BCTEXTLEN];
359 sprintf(string, "BATCHRENDER_COLUMN%d", i);
360 defaults->update(string, column_width[i]);
362 // defaults->update("BATCHRENDER_JOB", current_job);
364 mwindow->save_defaults();
369 char* BatchRenderThread::create_path(char *string)
372 sprintf(string, "%s", BCASTDIR);
373 fs.complete_path(string);
374 strcat(string, BATCH_PATH);
378 void BatchRenderThread::new_job()
380 BatchRenderJob *result = new BatchRenderJob(mwindow->preferences);
381 result->copy_from(get_current_job());
383 current_job = jobs.total - 1;
388 void BatchRenderThread::delete_job()
390 if(current_job < jobs.total && current_job >= 0)
392 jobs.remove_object_number(current_job);
393 if(current_job > 0) current_job--;
399 void BatchRenderThread::use_current_edl()
401 // printf("BatchRenderThread::use_current_edl %d %p %s\n",
403 // mwindow->edl->path,
404 // mwindow->edl->path);
406 strcpy(get_current_edl(), mwindow->edl->path);
408 gui->edl_path_text->update(get_current_edl());
411 void BatchRenderThread::update_selected_edl()
414 char *path = get_current_edl();
415 EDL *edl = mwindow->edl;
416 edl->save_xml(&xml_file, path, 0, 0);
417 xml_file.terminate_string();
418 if( xml_file.write_to_file(path) ) {
420 sprintf(msg, _("Unable to save: %s"), path);
421 MainError::show_error(msg);
425 BatchRenderJob* BatchRenderThread::get_current_job()
427 BatchRenderJob *result;
428 if(current_job >= jobs.total || current_job < 0)
430 result = default_job;
434 result = jobs.values[current_job];
440 Asset* BatchRenderThread::get_current_asset()
442 return get_current_job()->asset;
445 char* BatchRenderThread::get_current_edl()
447 return get_current_job()->edl_path;
451 // Test EDL files for existence
452 int BatchRenderThread::test_edl_files()
454 for(int i = 0; i < jobs.total; i++)
456 if(jobs.values[i]->enabled)
458 const char *path = jobs.values[i]->edl_path;
459 if( *path == '@' ) ++path;
460 FILE *fd = fopen(path, "r");
463 char string[BCTEXTLEN];
464 sprintf(string, _("EDL %s not found.\n"), jobs.values[i]->edl_path);
467 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
468 mwindow->gui->get_abs_cursor_x(1),
469 mwindow->gui->get_abs_cursor_y(1));
470 error_box.create_objects(string);
471 error_box.run_window();
472 gui->button_enable();
493 void BatchRenderThread::calculate_dest_paths(ArrayList<char*> *paths,
494 Preferences *preferences)
496 for(int i = 0; i < jobs.total; i++)
498 BatchRenderJob *job = jobs.values[i];
499 if(job->enabled && *job->edl_path != '@')
501 PackageDispatcher *packages = new PackageDispatcher;
504 TransportCommand *command = new TransportCommand;
505 FileXML *file = new FileXML;
506 file->read_from_file(job->edl_path);
508 // Use command to calculate range.
509 command->command = NORMAL_FWD;
510 command->get_edl()->load_xml(file,
512 command->change_type = CHANGE_ALL;
513 command->set_playback_range();
514 command->adjust_playback_range();
516 // Create test packages
517 packages->create_packages(mwindow,
522 command->start_position,
523 command->end_position,
526 // Append output paths allocated to total
527 for(int j = 0; j < packages->get_total_packages(); j++)
529 RenderPackage *package = packages->get_package(j);
530 paths->append(cstrdup(package->path));
533 // Delete package harness
542 void BatchRenderThread::start_rendering(char *config_path,
545 BC_Hash *boot_defaults;
546 Preferences *preferences;
548 BC_Signals *signals = new BC_Signals;
549 // XXX the above stuff is leaked,
551 // Initialize stuff which MWindow does.
552 signals->initialize();
553 MWindow::init_defaults(boot_defaults, config_path);
554 load_defaults(boot_defaults);
555 preferences = new Preferences;
556 preferences->load_defaults(boot_defaults);
557 MWindow::init_plugins(0, preferences);
558 char font_path[BCTEXTLEN];
559 strcpy(font_path, preferences->plugin_dir);
560 strcat(font_path, "/fonts");
561 BC_Resources::init_fontconfig(font_path);
562 BC_WindowBase::get_resources()->vframe_shm = 1;
565 load_jobs(batch_path, preferences);
566 save_jobs(batch_path);
567 save_defaults(boot_defaults);
570 // Test EDL files for existence
571 if(test_edl_files()) return;
575 // Predict all destination paths
576 ArrayList<char*> paths;
577 paths.set_array_delete();
578 calculate_dest_paths(&paths, preferences);
581 int result = ConfirmSave::test_files(0, &paths);
582 paths.remove_all_objects();
583 // Abort on any existing file because it's so hard to set this up.
587 render = new Render(0);
589 render->start_batches(&jobs,
595 void BatchRenderThread::start_rendering()
597 if(is_rendering) return;
600 char path[BCTEXTLEN];
603 save_defaults(mwindow->defaults);
604 gui->button_disable();
606 // Test EDL files for existence
607 if(test_edl_files()) return;
609 // Predict all destination paths
610 ArrayList<char*> paths;
611 calculate_dest_paths(&paths,
612 mwindow->preferences);
614 // Test destination files for overwrite
615 int result = ConfirmSave::test_files(mwindow, &paths);
616 paths.remove_all_objects();
622 gui->button_enable();
626 mwindow->render->start_batches(&jobs);
629 void BatchRenderThread::stop_rendering()
631 if(!is_rendering) return;
632 mwindow->render->stop_operation();
636 void BatchRenderThread::update_active(int number)
638 gui->lock_window("BatchRenderThread::update_active");
641 current_job = number;
642 rendering_job = number;
650 gui->unlock_window();
653 void BatchRenderThread::update_done(int number,
657 gui->lock_window("BatchRenderThread::update_done");
660 gui->button_enable();
664 jobs.values[number]->enabled = 0;
665 jobs.values[number]->elapsed = elapsed_time;
666 if(create_list) gui->create_list(1);
668 gui->unlock_window();
671 void BatchRenderThread::move_batch(int src, int dst)
673 BatchRenderJob *src_job = jobs.values[src];
674 if(dst < 0) dst = jobs.total - 1;
678 for(int i = src; i < jobs.total - 1; i++)
679 jobs.values[i] = jobs.values[i + 1];
680 // if(dst > src) dst--;
681 for(int i = jobs.total - 1; i > dst; i--)
682 jobs.values[i] = jobs.values[i - 1];
683 jobs.values[dst] = src_job;
694 BatchRenderGUI::BatchRenderGUI(MWindow *mwindow,
695 BatchRenderThread *thread,
700 : BC_Window(_(PROGRAM_NAME ": Batch Render"),
711 this->mwindow = mwindow;
712 this->thread = thread;
715 BatchRenderGUI::~BatchRenderGUI()
717 lock_window("BatchRenderGUI::~BatchRenderGUI");
723 void BatchRenderGUI::create_objects()
725 lock_window("BatchRenderGUI::create_objects");
726 mwindow->theme->get_batchrender_sizes(this, get_w(), get_h());
729 int x = mwindow->theme->batchrender_x1;
731 int x1 = mwindow->theme->batchrender_x1;
732 int x2 = mwindow->theme->batchrender_x2;
733 //int x3 = mwindow->theme->batchrender_x3;
738 add_subwindow(output_path_title = new BC_Title(x1, y, _("Output path:")));
740 format_tools = new BatchFormat(mwindow,
742 thread->get_current_asset());
743 format_tools->set_w(get_w() / 2);
744 format_tools->create_objects(x,
754 &thread->get_current_job()->strategy,
759 x += format_tools->get_w();
766 add_subwindow(edl_path_title = new BC_Title(x, y, _("EDL Path:")));
768 add_subwindow(edl_path_text = new BatchRenderEDLPath(
773 thread->get_current_edl()));
775 x += edl_path_text->get_w();
776 add_subwindow(edl_path_browse = new BrowseButton(
782 thread->get_current_edl(),
784 _("Select an EDL to load:"),
790 add_subwindow(update_selected_edl = new BatchRenderUpdateEDL(thread,
793 y += update_selected_edl->get_h() + mwindow->theme->widget_border;
795 add_subwindow(new_batch = new BatchRenderNew(thread,
798 x += new_batch->get_w() + 10;
800 add_subwindow(delete_batch = new BatchRenderDelete(thread,
803 x = new_batch->get_x();
804 y += new_batch->get_h() + mwindow->theme->widget_border;
805 add_subwindow(use_current_edl = new BatchRenderCurrentEDL(thread,
808 if( !mwindow->edl || !mwindow->edl->path[0] ) use_current_edl->disable();
812 add_subwindow(list_title = new BC_Title(x, y, _("Batches to render:")));
814 add_subwindow(batch_list = new BatchRenderList(thread,
818 get_h() - y - BC_GenericButton::calculate_h() - 15));
820 y += batch_list->get_h() + 10;
821 add_subwindow(start_button = new BatchRenderStart(thread,
825 BC_GenericButton::calculate_w(this, _("Stop")) / 2;
826 add_subwindow(stop_button = new BatchRenderStop(thread,
830 BC_GenericButton::calculate_w(this, _("Close")) -
832 add_subwindow(cancel_button = new BatchRenderCancel(thread,
840 void BatchRenderGUI::button_disable()
842 new_batch->disable();
843 delete_batch->disable();
844 use_current_edl->disable();
845 update_selected_edl->disable();
848 void BatchRenderGUI::button_enable()
851 delete_batch->enable();
852 if( mwindow->edl && mwindow->edl->path[0] )
853 use_current_edl->enable();
854 update_selected_edl->enable();
857 int BatchRenderGUI::resize_event(int w, int h)
859 mwindow->session->batchrender_w = w;
860 mwindow->session->batchrender_h = h;
861 mwindow->theme->get_batchrender_sizes(this, w, h);
863 int x = mwindow->theme->batchrender_x1;
865 int x1 = mwindow->theme->batchrender_x1;
866 int x2 = mwindow->theme->batchrender_x2;
867 //int x3 = mwindow->theme->batchrender_x3;
871 output_path_title->reposition_window(x1, y);
873 format_tools->reposition_window(x, y);
877 x += format_tools->get_w();
882 edl_path_title->reposition_window(x, y);
884 edl_path_text->reposition_window(x, y, w - x - 40);
885 x += edl_path_text->get_w();
886 edl_path_browse->reposition_window(x, y);
890 // status_title->reposition_window(x, y);
892 // status_text->reposition_window(x, y);
895 // progress_bar->reposition_window(x, y, w - x - 10);
898 update_selected_edl->reposition_window(x, y);
899 y += update_selected_edl->get_h() + mwindow->theme->widget_border;
900 new_batch->reposition_window(x, y);
901 x += new_batch->get_w() + 10;
902 delete_batch->reposition_window(x, y);
903 x = new_batch->get_x();
904 y += new_batch->get_h() + mwindow->theme->widget_border;
905 use_current_edl->reposition_window(x, y);
909 int y_margin = get_h() - batch_list->get_h();
910 list_title->reposition_window(x, y);
912 batch_list->reposition_window(x, y, w - x - 10, h - y_margin);
914 y += batch_list->get_h() + 10;
915 start_button->reposition_window(x, y);
917 stop_button->get_w() / 2;
918 stop_button->reposition_window(x, y);
920 cancel_button->get_w() -
922 cancel_button->reposition_window(x, y);
926 int BatchRenderGUI::translation_event()
928 mwindow->session->batchrender_x = get_x();
929 mwindow->session->batchrender_y = get_y();
933 int BatchRenderGUI::close_event()
935 // Stop batch rendering
937 thread->stop_rendering();
938 lock_window("BatchRenderGUI::close_event");
943 void BatchRenderGUI::create_list(int update_widget)
945 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
947 list_columns[i].remove_all_objects();
950 for(int i = 0; i < thread->jobs.total; i++)
952 BatchRenderJob *job = thread->jobs.values[i];
953 char string[BCTEXTLEN];
954 BC_ListBoxItem *enabled = new BC_ListBoxItem(job->enabled ?
957 BC_ListBoxItem *item1 = new BC_ListBoxItem(job->asset->path);
958 BC_ListBoxItem *item2 = new BC_ListBoxItem(job->edl_path);
959 BC_ListBoxItem *item3;
961 item3 = new BC_ListBoxItem(
962 Units::totext(string,
966 item3 = new BC_ListBoxItem(_("Unknown"));
967 list_columns[0].append(enabled);
968 list_columns[1].append(item1);
969 list_columns[2].append(item2);
970 list_columns[3].append(item3);
971 if(i == thread->current_job)
973 enabled->set_selected(1);
974 item1->set_selected(1);
975 item2->set_selected(1);
976 item3->set_selected(1);
978 if(i == thread->rendering_job)
980 enabled->set_color(RED);
981 item1->set_color(RED);
982 item2->set_color(RED);
983 item3->set_color(RED);
989 batch_list->update(list_columns,
991 thread->column_width,
993 batch_list->get_xposition(),
994 batch_list->get_yposition(),
995 batch_list->get_highlighted_item(), // Flat index of item cursor is over
996 1, // set all autoplace flags to 1
1001 void BatchRenderGUI::change_job()
1003 BatchRenderJob *job = thread->get_current_job();
1004 format_tools->update(job->asset, &job->strategy);
1005 edl_path_text->update(job->edl_path);
1015 BatchFormat::BatchFormat(MWindow *mwindow,
1016 BatchRenderGUI *gui,
1018 : FormatTools(mwindow, gui, asset)
1021 this->mwindow = mwindow;
1024 BatchFormat::~BatchFormat()
1029 int BatchFormat::handle_event()
1031 gui->create_list(1);
1045 BatchRenderEDLPath::BatchRenderEDLPath(BatchRenderThread *thread,
1056 this->thread = thread;
1060 int BatchRenderEDLPath::handle_event()
1063 calculate_suggestions(thread->file_entries);
1065 strcpy(thread->get_current_edl(), get_text());
1066 thread->gui->create_list(1);
1075 BatchRenderNew::BatchRenderNew(BatchRenderThread *thread,
1078 : BC_GenericButton(x, y, _("New"))
1080 this->thread = thread;
1083 int BatchRenderNew::handle_event()
1089 BatchRenderDelete::BatchRenderDelete(BatchRenderThread *thread,
1092 : BC_GenericButton(x, y, _("Delete"))
1094 this->thread = thread;
1097 int BatchRenderDelete::handle_event()
1099 thread->delete_job();
1108 BatchRenderCurrentEDL::BatchRenderCurrentEDL(BatchRenderThread *thread,
1111 : BC_GenericButton(x, y, _("Use Current EDL"))
1113 this->thread = thread;
1116 int BatchRenderCurrentEDL::handle_event()
1118 thread->use_current_edl();
1122 BatchRenderUpdateEDL::BatchRenderUpdateEDL(BatchRenderThread *thread,
1125 : BC_GenericButton(x, y, _("Save to EDL Path"))
1127 this->thread = thread;
1130 int BatchRenderUpdateEDL::handle_event()
1132 thread->update_selected_edl();
1139 BatchRenderList::BatchRenderList(BatchRenderThread *thread,
1149 thread->gui->list_columns,
1151 thread->column_width,
1152 BATCHRENDER_COLUMNS,
1159 this->thread = thread;
1161 set_process_drag(0);
1164 int BatchRenderList::handle_event()
1169 int BatchRenderList::selection_changed()
1171 thread->current_job = get_selection_number(0, 0);
1172 thread->gui->change_job();
1173 if(get_cursor_x() < thread->column_width[0])
1175 BatchRenderJob *job = thread->get_current_job();
1176 job->enabled = !job->enabled;
1177 thread->gui->create_list(1);
1182 int BatchRenderList::column_resize_event()
1184 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
1186 thread->column_width[i] = get_column_width(i);
1191 int BatchRenderList::drag_start_event()
1193 if(BC_ListBox::drag_start_event())
1202 int BatchRenderList::drag_motion_event()
1204 if(BC_ListBox::drag_motion_event())
1211 int BatchRenderList::drag_stop_event()
1215 int src = get_selection_number(0, 0);
1216 int dst = get_highlighted_item();
1219 thread->move_batch(src, dst);
1221 BC_ListBox::drag_stop_event();
1238 BatchRenderStart::BatchRenderStart(BatchRenderThread *thread,
1241 : BC_GenericButton(x,
1245 this->thread = thread;
1248 int BatchRenderStart::handle_event()
1250 thread->start_rendering();
1254 BatchRenderStop::BatchRenderStop(BatchRenderThread *thread,
1257 : BC_GenericButton(x,
1261 this->thread = thread;
1264 int BatchRenderStop::handle_event()
1267 thread->stop_rendering();
1268 lock_window("BatchRenderStop::handle_event");
1273 BatchRenderCancel::BatchRenderCancel(BatchRenderThread *thread,
1276 : BC_GenericButton(x,
1280 this->thread = thread;
1283 int BatchRenderCancel::handle_event()
1286 thread->stop_rendering();
1287 lock_window("BatchRenderCancel::handle_event");
1288 thread->gui->set_done(1);
1292 int BatchRenderCancel::keypress_event()
1294 if(get_keypress() == ESC)
1297 thread->stop_rendering();
1298 lock_window("BatchRenderCancel::keypress_event");
1299 thread->gui->set_done(1);