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"
61 #include <sys/statfs.h>
65 static const char *list_titles[] =
73 static int list_widths[] =
81 BatchRenderMenuItem::BatchRenderMenuItem(MWindow *mwindow)
82 : BC_MenuItem(_("Batch Render..."), "Shift-B", 'B')
85 this->mwindow = mwindow;
88 int BatchRenderMenuItem::handle_event()
90 mwindow->batch_render->start();
101 BatchRenderJob::BatchRenderJob(Preferences *preferences)
103 this->preferences = preferences;
111 BatchRenderJob::~BatchRenderJob()
113 asset->Garbage::remove_user();
116 void BatchRenderJob::copy_from(BatchRenderJob *src)
118 asset->copy_from(src->asset, 0);
119 strcpy(edl_path, src->edl_path);
120 strategy = src->strategy;
121 enabled = src->enabled;
125 void BatchRenderJob::load(FileXML *file)
130 file->tag.get_property("EDL_PATH", edl_path);
131 strategy = file->tag.get_property("STRATEGY", strategy);
132 enabled = file->tag.get_property("ENABLED", enabled);
133 elapsed = file->tag.get_property("ELAPSED", elapsed);
136 result = file->read_tag();
139 if(file->tag.title_is("ASSET"))
141 file->tag.get_property("SRC", asset->path);
142 asset->read(file, 0);
143 // The compression parameters are stored in the defaults to reduce
144 // coding maintenance. The defaults must now be stuffed into the XML for
147 defaults.load_string(file->read_text());
148 asset->load_defaults(&defaults,
159 void BatchRenderJob::save(FileXML *file)
161 file->tag.set_property("EDL_PATH", edl_path);
162 file->tag.set_property("STRATEGY", strategy);
163 file->tag.set_property("ENABLED", enabled);
164 file->tag.set_property("ELAPSED", elapsed);
166 file->append_newline();
171 // The compression parameters are stored in the defaults to reduce
172 // coding maintenance. The defaults must now be stuffed into the XML for
175 asset->save_defaults(&defaults,
183 defaults.save_string(string);
184 file->append_text(string);
186 file->tag.set_title("/JOB");
188 file->append_newline();
191 void BatchRenderJob::fix_strategy()
193 strategy = Render::fix_strategy(strategy, preferences->use_renderfarm);
205 BatchRenderThread::BatchRenderThread(MWindow *mwindow)
208 this->mwindow = mwindow;
216 BatchRenderThread::BatchRenderThread()
227 void BatchRenderThread::handle_close_event(int result)
230 char path[BCTEXTLEN];
233 save_defaults(mwindow->defaults);
236 jobs.remove_all_objects();
239 file_entries->remove_all_objects();
245 BC_Window* BatchRenderThread::new_gui()
249 default_job = new BatchRenderJob(mwindow->preferences);
254 file_entries = new ArrayList<BC_ListBoxItem*>;
256 char string[BCTEXTLEN];
257 // Load current directory
258 fs.update(getcwd(string, BCTEXTLEN));
259 for(int i = 0; i < fs.total_files(); i++)
261 file_entries->append(
263 fs.get_entry(i)->get_name()));
267 char path[BCTEXTLEN];
269 load_jobs(path, mwindow->preferences);
270 load_defaults(mwindow->defaults);
271 this->gui = new BatchRenderGUI(mwindow,
273 mwindow->session->batchrender_x,
274 mwindow->session->batchrender_y,
275 mwindow->session->batchrender_w,
276 mwindow->session->batchrender_h);
277 this->gui->create_objects();
282 void BatchRenderThread::load_jobs(char *path, Preferences *preferences)
287 jobs.remove_all_objects();
289 file.read_from_file(path);
291 file.read_from_file(create_path(path));
295 if(!(result = file.read_tag()))
297 if(file.tag.title_is("JOB"))
300 jobs.append(job = new BatchRenderJob(preferences));
307 void BatchRenderThread::save_jobs(char *path)
311 for(int i = 0; i < jobs.total; i++)
313 file.tag.set_title("JOB");
314 jobs.values[i]->save(&file);
318 file.write_to_file(path);
320 file.write_to_file(create_path(path));
323 void BatchRenderThread::load_defaults(BC_Hash *defaults)
327 default_job->asset->load_defaults(defaults,
334 default_job->fix_strategy();
337 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
339 char string[BCTEXTLEN];
340 sprintf(string, "BATCHRENDER_COLUMN%d", i);
341 column_width[i] = defaults->get(string, list_widths[i]);
345 void BatchRenderThread::save_defaults(BC_Hash *defaults)
349 default_job->asset->save_defaults(defaults,
356 defaults->update("BATCHRENDER_STRATEGY", default_job->strategy);
358 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
360 char string[BCTEXTLEN];
361 sprintf(string, "BATCHRENDER_COLUMN%d", i);
362 defaults->update(string, column_width[i]);
364 // defaults->update("BATCHRENDER_JOB", current_job);
366 mwindow->save_defaults();
371 char* BatchRenderThread::create_path(char *string)
374 sprintf(string, "%s", BCASTDIR);
375 fs.complete_path(string);
376 strcat(string, BATCH_PATH);
380 void BatchRenderThread::new_job()
382 BatchRenderJob *result = new BatchRenderJob(mwindow->preferences);
383 result->copy_from(get_current_job());
385 current_job = jobs.total - 1;
390 void BatchRenderThread::delete_job()
392 if(current_job < jobs.total && current_job >= 0)
394 jobs.remove_object_number(current_job);
395 if(current_job > 0) current_job--;
401 void BatchRenderThread::use_current_edl()
403 // printf("BatchRenderThread::use_current_edl %d %p %s\n",
405 // mwindow->edl->path,
406 // mwindow->edl->path);
408 strcpy(get_current_edl(), mwindow->edl->path);
410 gui->edl_path_text->update(get_current_edl());
413 void BatchRenderThread::update_selected_edl()
416 char *path = get_current_edl();
417 EDL *edl = mwindow->edl;
418 edl->save_xml(&xml_file, path, 0, 0);
419 xml_file.terminate_string();
420 if( xml_file.write_to_file(path) ) {
422 sprintf(msg, "Unable to save: %s", path);
423 MainError::show_error(msg);
427 BatchRenderJob* BatchRenderThread::get_current_job()
429 BatchRenderJob *result;
430 if(current_job >= jobs.total || current_job < 0)
432 result = default_job;
436 result = jobs.values[current_job];
442 Asset* BatchRenderThread::get_current_asset()
444 return get_current_job()->asset;
447 char* BatchRenderThread::get_current_edl()
449 return get_current_job()->edl_path;
453 // Test EDL files for existence
454 int BatchRenderThread::test_edl_files()
456 for(int i = 0; i < jobs.total; i++)
458 if(jobs.values[i]->enabled)
460 const char *path = jobs.values[i]->edl_path;
461 if( *path == '@' ) ++path;
462 FILE *fd = fopen(path, "r");
465 char string[BCTEXTLEN];
466 sprintf(string, _("EDL %s not found.\n"), jobs.values[i]->edl_path);
469 ErrorBox error_box(PROGRAM_NAME ": Error",
470 mwindow->gui->get_abs_cursor_x(1),
471 mwindow->gui->get_abs_cursor_y(1));
472 error_box.create_objects(string);
473 error_box.run_window();
474 gui->button_enable();
495 void BatchRenderThread::calculate_dest_paths(ArrayList<char*> *paths,
496 Preferences *preferences)
498 for(int i = 0; i < jobs.total; i++)
500 BatchRenderJob *job = jobs.values[i];
501 if(job->enabled && *job->edl_path != '@')
503 PackageDispatcher *packages = new PackageDispatcher;
506 TransportCommand *command = new TransportCommand;
507 FileXML *file = new FileXML;
508 file->read_from_file(job->edl_path);
510 // Use command to calculate range.
511 command->command = NORMAL_FWD;
512 command->get_edl()->load_xml(file,
514 command->change_type = CHANGE_ALL;
515 command->set_playback_range();
516 command->adjust_playback_range();
518 // Create test packages
519 packages->create_packages(mwindow,
524 command->start_position,
525 command->end_position,
528 // Append output paths allocated to total
529 for(int j = 0; j < packages->get_total_packages(); j++)
531 RenderPackage *package = packages->get_package(j);
532 paths->append(cstrdup(package->path));
535 // Delete package harness
544 void BatchRenderThread::start_rendering(char *config_path,
547 BC_Hash *boot_defaults;
548 Preferences *preferences;
550 BC_Signals *signals = new BC_Signals;
551 // XXX the above stuff is leaked,
553 // Initialize stuff which MWindow does.
554 signals->initialize();
555 MWindow::init_defaults(boot_defaults, config_path);
556 load_defaults(boot_defaults);
557 preferences = new Preferences;
558 preferences->load_defaults(boot_defaults);
559 MWindow::init_plugins(0, preferences);
560 char font_path[BCTEXTLEN];
561 strcpy(font_path, preferences->plugin_dir);
562 strcat(font_path, "/fonts");
563 BC_Resources::init_fontconfig(font_path);
564 BC_WindowBase::get_resources()->vframe_shm = 1;
565 MWindow::init_fileserver(preferences);
568 load_jobs(batch_path, preferences);
569 save_jobs(batch_path);
570 save_defaults(boot_defaults);
573 // Test EDL files for existence
574 if(test_edl_files()) return;
578 // Predict all destination paths
579 ArrayList<char*> paths;
580 paths.set_array_delete();
581 calculate_dest_paths(&paths, preferences);
584 int result = ConfirmSave::test_files(0, &paths);
585 paths.remove_all_objects();
586 // Abort on any existing file because it's so hard to set this up.
590 render = new Render(0);
592 render->start_batches(&jobs,
598 void BatchRenderThread::start_rendering()
600 if(is_rendering) return;
603 char path[BCTEXTLEN];
606 save_defaults(mwindow->defaults);
607 gui->button_disable();
609 // Test EDL files for existence
610 if(test_edl_files()) return;
612 // Predict all destination paths
613 ArrayList<char*> paths;
614 calculate_dest_paths(&paths,
615 mwindow->preferences);
617 // Test destination files for overwrite
618 int result = ConfirmSave::test_files(mwindow, &paths);
619 paths.remove_all_objects();
625 gui->button_enable();
629 mwindow->render->start_batches(&jobs);
632 void BatchRenderThread::stop_rendering()
634 if(!is_rendering) return;
635 mwindow->render->stop_operation();
639 void BatchRenderThread::update_active(int number)
641 gui->lock_window("BatchRenderThread::update_active");
644 current_job = number;
645 rendering_job = number;
653 gui->unlock_window();
656 void BatchRenderThread::update_done(int number,
660 gui->lock_window("BatchRenderThread::update_done");
663 gui->button_enable();
667 jobs.values[number]->enabled = 0;
668 jobs.values[number]->elapsed = elapsed_time;
669 if(create_list) gui->create_list(1);
671 gui->unlock_window();
674 void BatchRenderThread::move_batch(int src, int dst)
676 BatchRenderJob *src_job = jobs.values[src];
677 if(dst < 0) dst = jobs.total - 1;
681 for(int i = src; i < jobs.total - 1; i++)
682 jobs.values[i] = jobs.values[i + 1];
683 // if(dst > src) dst--;
684 for(int i = jobs.total - 1; i > dst; i--)
685 jobs.values[i] = jobs.values[i - 1];
686 jobs.values[dst] = src_job;
697 BatchRenderGUI::BatchRenderGUI(MWindow *mwindow,
698 BatchRenderThread *thread,
703 : BC_Window(PROGRAM_NAME ": Batch Render",
714 this->mwindow = mwindow;
715 this->thread = thread;
718 BatchRenderGUI::~BatchRenderGUI()
720 lock_window("BatchRenderGUI::~BatchRenderGUI");
726 void BatchRenderGUI::create_objects()
728 lock_window("BatchRenderGUI::create_objects");
729 mwindow->theme->get_batchrender_sizes(this, get_w(), get_h());
732 int x = mwindow->theme->batchrender_x1;
734 int x1 = mwindow->theme->batchrender_x1;
735 int x2 = mwindow->theme->batchrender_x2;
736 //int x3 = mwindow->theme->batchrender_x3;
741 add_subwindow(output_path_title = new BC_Title(x1, y, _("Output path:")));
743 format_tools = new BatchFormat(mwindow,
745 thread->get_current_asset());
746 format_tools->set_w(get_w() / 2);
747 format_tools->create_objects(x,
757 &thread->get_current_job()->strategy,
762 x += format_tools->get_w();
769 add_subwindow(edl_path_title = new BC_Title(x, y, _("EDL Path:")));
771 add_subwindow(edl_path_text = new BatchRenderEDLPath(
776 thread->get_current_edl()));
778 x += edl_path_text->get_w();
779 add_subwindow(edl_path_browse = new BrowseButton(
785 thread->get_current_edl(),
787 _("Select an EDL to load:"),
793 add_subwindow(update_selected_edl = new BatchRenderUpdateEDL(thread,
796 y += update_selected_edl->get_h() + mwindow->theme->widget_border;
798 add_subwindow(new_batch = new BatchRenderNew(thread,
801 x += new_batch->get_w() + 10;
803 add_subwindow(delete_batch = new BatchRenderDelete(thread,
806 x = new_batch->get_x();
807 y += new_batch->get_h() + mwindow->theme->widget_border;
808 add_subwindow(use_current_edl = new BatchRenderCurrentEDL(thread,
811 if( !mwindow->edl || !mwindow->edl->path[0] ) use_current_edl->disable();
815 add_subwindow(list_title = new BC_Title(x, y, _("Batches to render:")));
817 add_subwindow(batch_list = new BatchRenderList(thread,
821 get_h() - y - BC_GenericButton::calculate_h() - 15));
823 y += batch_list->get_h() + 10;
824 add_subwindow(start_button = new BatchRenderStart(thread,
828 BC_GenericButton::calculate_w(this, _("Stop")) / 2;
829 add_subwindow(stop_button = new BatchRenderStop(thread,
833 BC_GenericButton::calculate_w(this, _("Close")) -
835 add_subwindow(cancel_button = new BatchRenderCancel(thread,
843 void BatchRenderGUI::button_disable()
845 new_batch->disable();
846 delete_batch->disable();
847 use_current_edl->disable();
848 update_selected_edl->disable();
851 void BatchRenderGUI::button_enable()
854 delete_batch->enable();
855 if( mwindow->edl && mwindow->edl->path[0] )
856 use_current_edl->enable();
857 update_selected_edl->enable();
860 int BatchRenderGUI::resize_event(int w, int h)
862 mwindow->session->batchrender_w = w;
863 mwindow->session->batchrender_h = h;
864 mwindow->theme->get_batchrender_sizes(this, w, h);
866 int x = mwindow->theme->batchrender_x1;
868 int x1 = mwindow->theme->batchrender_x1;
869 int x2 = mwindow->theme->batchrender_x2;
870 //int x3 = mwindow->theme->batchrender_x3;
874 output_path_title->reposition_window(x1, y);
876 format_tools->reposition_window(x, y);
880 x += format_tools->get_w();
885 edl_path_title->reposition_window(x, y);
887 edl_path_text->reposition_window(x, y, w - x - 40);
888 x += edl_path_text->get_w();
889 edl_path_browse->reposition_window(x, y);
893 // status_title->reposition_window(x, y);
895 // status_text->reposition_window(x, y);
898 // progress_bar->reposition_window(x, y, w - x - 10);
901 update_selected_edl->reposition_window(x, y);
902 y += update_selected_edl->get_h() + mwindow->theme->widget_border;
903 new_batch->reposition_window(x, y);
904 x += new_batch->get_w() + 10;
905 delete_batch->reposition_window(x, y);
906 x = new_batch->get_x();
907 y += new_batch->get_h() + mwindow->theme->widget_border;
908 use_current_edl->reposition_window(x, y);
912 int y_margin = get_h() - batch_list->get_h();
913 list_title->reposition_window(x, y);
915 batch_list->reposition_window(x, y, w - x - 10, h - y_margin);
917 y += batch_list->get_h() + 10;
918 start_button->reposition_window(x, y);
920 stop_button->get_w() / 2;
921 stop_button->reposition_window(x, y);
923 cancel_button->get_w() -
925 cancel_button->reposition_window(x, y);
929 int BatchRenderGUI::translation_event()
931 mwindow->session->batchrender_x = get_x();
932 mwindow->session->batchrender_y = get_y();
936 int BatchRenderGUI::close_event()
938 // Stop batch rendering
940 thread->stop_rendering();
941 lock_window("BatchRenderGUI::close_event");
946 void BatchRenderGUI::create_list(int update_widget)
948 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
950 list_columns[i].remove_all_objects();
953 for(int i = 0; i < thread->jobs.total; i++)
955 BatchRenderJob *job = thread->jobs.values[i];
956 char string[BCTEXTLEN];
957 BC_ListBoxItem *enabled = new BC_ListBoxItem(job->enabled ?
960 BC_ListBoxItem *item1 = new BC_ListBoxItem(job->asset->path);
961 BC_ListBoxItem *item2 = new BC_ListBoxItem(job->edl_path);
962 BC_ListBoxItem *item3;
964 item3 = new BC_ListBoxItem(
965 Units::totext(string,
969 item3 = new BC_ListBoxItem(_("Unknown"));
970 list_columns[0].append(enabled);
971 list_columns[1].append(item1);
972 list_columns[2].append(item2);
973 list_columns[3].append(item3);
974 if(i == thread->current_job)
976 enabled->set_selected(1);
977 item1->set_selected(1);
978 item2->set_selected(1);
979 item3->set_selected(1);
981 if(i == thread->rendering_job)
983 enabled->set_color(RED);
984 item1->set_color(RED);
985 item2->set_color(RED);
986 item3->set_color(RED);
992 batch_list->update(list_columns,
994 thread->column_width,
996 batch_list->get_xposition(),
997 batch_list->get_yposition(),
998 batch_list->get_highlighted_item(), // Flat index of item cursor is over
999 1, // set all autoplace flags to 1
1004 void BatchRenderGUI::change_job()
1006 BatchRenderJob *job = thread->get_current_job();
1007 format_tools->update(job->asset, &job->strategy);
1008 edl_path_text->update(job->edl_path);
1018 BatchFormat::BatchFormat(MWindow *mwindow,
1019 BatchRenderGUI *gui,
1021 : FormatTools(mwindow, gui, asset)
1024 this->mwindow = mwindow;
1027 BatchFormat::~BatchFormat()
1032 int BatchFormat::handle_event()
1034 gui->create_list(1);
1048 BatchRenderEDLPath::BatchRenderEDLPath(BatchRenderThread *thread,
1059 this->thread = thread;
1063 int BatchRenderEDLPath::handle_event()
1066 calculate_suggestions(thread->file_entries);
1068 strcpy(thread->get_current_edl(), get_text());
1069 thread->gui->create_list(1);
1078 BatchRenderNew::BatchRenderNew(BatchRenderThread *thread,
1081 : BC_GenericButton(x, y, _("New"))
1083 this->thread = thread;
1086 int BatchRenderNew::handle_event()
1092 BatchRenderDelete::BatchRenderDelete(BatchRenderThread *thread,
1095 : BC_GenericButton(x, y, _("Delete"))
1097 this->thread = thread;
1100 int BatchRenderDelete::handle_event()
1102 thread->delete_job();
1111 BatchRenderCurrentEDL::BatchRenderCurrentEDL(BatchRenderThread *thread,
1114 : BC_GenericButton(x, y, _("Use Current EDL"))
1116 this->thread = thread;
1119 int BatchRenderCurrentEDL::handle_event()
1121 thread->use_current_edl();
1125 BatchRenderUpdateEDL::BatchRenderUpdateEDL(BatchRenderThread *thread,
1128 : BC_GenericButton(x, y, _("Save to EDL Path"))
1130 this->thread = thread;
1133 int BatchRenderUpdateEDL::handle_event()
1135 thread->update_selected_edl();
1142 BatchRenderList::BatchRenderList(BatchRenderThread *thread,
1152 thread->gui->list_columns,
1154 thread->column_width,
1155 BATCHRENDER_COLUMNS,
1162 this->thread = thread;
1164 set_process_drag(0);
1167 int BatchRenderList::handle_event()
1172 int BatchRenderList::selection_changed()
1174 thread->current_job = get_selection_number(0, 0);
1175 thread->gui->change_job();
1176 if(get_cursor_x() < thread->column_width[0])
1178 BatchRenderJob *job = thread->get_current_job();
1179 job->enabled = !job->enabled;
1180 thread->gui->create_list(1);
1185 int BatchRenderList::column_resize_event()
1187 for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
1189 thread->column_width[i] = get_column_width(i);
1194 int BatchRenderList::drag_start_event()
1196 if(BC_ListBox::drag_start_event())
1205 int BatchRenderList::drag_motion_event()
1207 if(BC_ListBox::drag_motion_event())
1214 int BatchRenderList::drag_stop_event()
1218 int src = get_selection_number(0, 0);
1219 int dst = get_highlighted_item();
1222 thread->move_batch(src, dst);
1224 BC_ListBox::drag_stop_event();
1241 BatchRenderStart::BatchRenderStart(BatchRenderThread *thread,
1244 : BC_GenericButton(x,
1248 this->thread = thread;
1251 int BatchRenderStart::handle_event()
1253 thread->start_rendering();
1257 BatchRenderStop::BatchRenderStop(BatchRenderThread *thread,
1260 : BC_GenericButton(x,
1264 this->thread = thread;
1267 int BatchRenderStop::handle_event()
1270 thread->stop_rendering();
1271 lock_window("BatchRenderStop::handle_event");
1276 BatchRenderCancel::BatchRenderCancel(BatchRenderThread *thread,
1279 : BC_GenericButton(x,
1283 this->thread = thread;
1286 int BatchRenderCancel::handle_event()
1289 thread->stop_rendering();
1290 lock_window("BatchRenderCancel::handle_event");
1291 thread->gui->set_done(1);
1295 int BatchRenderCancel::keypress_event()
1297 if(get_keypress() == ESC)
1300 thread->stop_rendering();
1301 lock_window("BatchRenderCancel::keypress_event");
1302 thread->gui->set_done(1);
1314 const int64_t CreateDVD_Thread::DVD_SIZE = 4700000000;
1315 const int CreateDVD_Thread::DVD_STREAMS = 1;
1316 const int CreateDVD_Thread::DVD_WIDTH = 720;
1317 const int CreateDVD_Thread::DVD_HEIGHT = 480;
1318 const double CreateDVD_Thread::DVD_ASPECT_WIDTH = 4.;
1319 const double CreateDVD_Thread::DVD_ASPECT_HEIGHT = 3.;
1320 const double CreateDVD_Thread::DVD_WIDE_ASPECT_WIDTH = 16.;
1321 const double CreateDVD_Thread::DVD_WIDE_ASPECT_HEIGHT = 9.;
1322 const double CreateDVD_Thread::DVD_FRAMERATE = 30000. / 1001.;
1323 const int CreateDVD_Thread::DVD_MAX_BITRATE = 8000000;
1324 const int CreateDVD_Thread::DVD_CHANNELS = 2;
1325 const int CreateDVD_Thread::DVD_WIDE_CHANNELS = 6;
1326 const double CreateDVD_Thread::DVD_SAMPLERATE = 48000;
1327 const double CreateDVD_Thread::DVD_KAUDIO_RATE = 224;
1330 CreateDVD_MenuItem::CreateDVD_MenuItem(MWindow *mwindow)
1331 : BC_MenuItem(_("DVD Render..."), "Shift-D", 'D')
1334 this->mwindow = mwindow;
1337 int CreateDVD_MenuItem::handle_event()
1339 mwindow->create_dvd->start();
1344 CreateDVD_Thread::CreateDVD_Thread(MWindow *mwindow)
1347 this->mwindow = mwindow;
1349 this->use_deinterlace = 0;
1350 this->use_inverse_telecine = 0;
1351 this->use_scale = 0;
1352 this->use_resize_tracks = 0;
1353 this->use_histogram = 0;
1354 this->use_wide_audio = 0;
1355 this->use_wide_aspect = 0;
1356 this->use_label_chapters = 0;
1359 CreateDVD_Thread::~CreateDVD_Thread()
1363 int CreateDVD_Thread::create_dvd_jobs(ArrayList<BatchRenderJob*> *jobs,
1364 const char *tmp_path, const char *asset_title)
1366 EDL *edl = mwindow->edl;
1367 if( !edl || !edl->session ) {
1368 char msg[BCTEXTLEN];
1369 sprintf(msg, "No EDL/Session");
1370 MainError::show_error(msg);
1373 EDLSession *session = edl->session;
1375 double total_length = edl->tracks->total_length();
1376 if( total_length <= 0 ) {
1377 char msg[BCTEXTLEN];
1378 sprintf(msg, "No content: %s", asset_title);
1379 MainError::show_error(msg);
1383 char asset_dir[BCTEXTLEN];
1384 sprintf(asset_dir, "%s/%s", tmp_path, asset_title);
1386 if( mkdir(asset_dir, 0777) ) {
1387 char err[BCTEXTLEN], msg[BCTEXTLEN];
1388 strerror_r(errno, err, sizeof(err));
1389 sprintf(msg, "Unable to create directory: %s\n-- %s", asset_dir, err);
1390 MainError::show_error(msg);
1394 double old_samplerate = session->sample_rate;
1395 double old_framerate = session->frame_rate;
1397 session->video_channels = DVD_STREAMS;
1398 session->video_tracks = DVD_STREAMS;
1399 session->frame_rate = DVD_FRAMERATE;
1400 session->output_w = DVD_WIDTH;
1401 session->output_h = DVD_HEIGHT;
1402 session->aspect_w = use_wide_aspect ? DVD_WIDE_ASPECT_WIDTH : DVD_ASPECT_WIDTH;
1403 session->aspect_h = use_wide_aspect ? DVD_WIDE_ASPECT_HEIGHT : DVD_ASPECT_HEIGHT;
1404 session->sample_rate = DVD_SAMPLERATE;
1405 session->audio_channels = session->audio_tracks =
1406 use_wide_audio ? DVD_WIDE_CHANNELS : DVD_CHANNELS;
1408 char script_filename[BCTEXTLEN];
1409 sprintf(script_filename, "%s/dvd.sh", asset_dir);
1410 int fd = open(script_filename, O_WRONLY+O_CREAT+O_TRUNC, 0755);
1411 FILE *fp = fdopen(fd, "w");
1413 char err[BCTEXTLEN], msg[BCTEXTLEN];
1414 strerror_r(errno, err, sizeof(err));
1415 sprintf(msg, "Unable to save: %s\n-- %s", script_filename, err);
1416 MainError::show_error(msg);
1419 fprintf(fp,"#!/bin/bash\n");
1420 fprintf(fp,"echo \"running %s\" $# $*\n", script_filename);
1422 fprintf(fp,"mplex -f 8 -o $1/dvd.mpg $1/dvd.m2v $1/dvd.ac3\n");
1424 fprintf(fp,"rm -rf $1/iso\n");
1425 fprintf(fp,"mkdir -p $1/iso\n");
1427 fprintf(fp,"dvdauthor -x - <<eof\n");
1428 fprintf(fp,"<dvdauthor dest=\"$1/iso\">\n");
1429 fprintf(fp," <vmgm>\n");
1430 fprintf(fp," <fpc> jump title 1; </fpc>\n");
1431 fprintf(fp," </vmgm>\n");
1432 fprintf(fp," <titleset>\n");
1433 fprintf(fp," <titles>\n");
1434 fprintf(fp," <video format=\"ntsc\" aspect=\"%d:%d\" resolution=\"%dx%d\"/>\n",
1435 (int)session->aspect_w, (int)session->aspect_h,
1436 session->output_w, session->output_h);
1437 fprintf(fp," <audio format=\"ac3\" lang=\"en\"/>\n");
1438 fprintf(fp," <pgc>\n");
1439 fprintf(fp," <vob file=\"$1/dvd.mpg\" chapters=\"");
1440 if( use_label_chapters && edl->labels ) {
1441 Label *label = edl->labels->first;
1443 int secs = label->position;
1444 int mins = secs / 60;
1445 int frms = (label->position-secs) * session->frame_rate;
1446 fprintf(fp,"%d:%02d:%02d.%d", mins/60, mins%60, secs%60, frms);
1447 if( (label=label->next) != 0 ) fprintf(fp, ",");
1452 for( int secs=0 ; secs<total_length; secs+=10*60 ) {
1454 fprintf(fp,"%d:%02d:00,", mins/60, mins%60);
1456 fprintf(fp,"%d:%02d:00", mins/60, mins%60);
1458 fprintf(fp,"\"/>\n");
1459 fprintf(fp," </pgc>\n");
1460 fprintf(fp," </titles>\n");
1461 fprintf(fp," </titleset>\n");
1462 fprintf(fp,"</dvdauthor>\n");
1463 fprintf(fp,"eof\n");
1465 fprintf(fp,"echo To burn dvd, load blank media and run:\n");
1466 fprintf(fp,"echo growisofs -dvd-compat -Z /dev/dvd -dvd-video $1/iso\n");
1470 if( use_wide_audio ) {
1471 session->audio_channels = session->audio_tracks = DVD_WIDE_CHANNELS;
1472 session->achannel_positions[0] = 90;
1473 session->achannel_positions[1] = 150;
1474 session->achannel_positions[2] = 30;
1475 session->achannel_positions[3] = 210;
1476 session->achannel_positions[4] = 330;
1477 session->achannel_positions[5] = 270;
1478 if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
1479 mwindow->remap_audio(MWindow::AUDIO_1_TO_1);
1482 session->audio_channels = session->audio_tracks = DVD_CHANNELS;
1483 session->achannel_positions[0] = 180;
1484 session->achannel_positions[1] = 0;
1485 if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
1486 mwindow->remap_audio(MWindow::AUDIO_5_1_TO_2);
1489 double new_samplerate = session->sample_rate;
1490 double new_framerate = session->frame_rate;
1492 edl->resample(old_samplerate, new_samplerate, TRACK_AUDIO);
1493 edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
1495 int64_t aud_size = ((DVD_KAUDIO_RATE * total_length)/8 + 1000-1) * 1000;
1496 int64_t vid_size = DVD_SIZE*0.96 - aud_size;
1497 int vid_bitrate = (vid_size * 8) / total_length;
1498 vid_bitrate /= 1000; vid_bitrate *= 1000;
1499 if( vid_bitrate > DVD_MAX_BITRATE ) vid_bitrate = DVD_MAX_BITRATE;
1501 char xml_filename[BCTEXTLEN];
1502 sprintf(xml_filename, "%s/dvd.xml", asset_dir);
1504 edl->save_xml(&xml_file, xml_filename, 0, 0);
1505 xml_file.terminate_string();
1506 if( xml_file.write_to_file(xml_filename) ) {
1507 char msg[BCTEXTLEN];
1508 sprintf(msg, "Unable to save: %s", xml_filename);
1509 MainError::show_error(msg);
1513 BatchRenderJob *job = new BatchRenderJob(mwindow->preferences);
1515 strcpy(&job->edl_path[0], xml_filename);
1516 Asset *asset = job->asset;
1518 sprintf(&asset->path[0],"%s/dvd.m2v", asset_dir);
1519 asset->video_data = 1;
1520 asset->format = FILE_VMPEG;
1521 asset->layers = DVD_STREAMS;
1522 asset->frame_rate = session->frame_rate;
1523 asset->width = session->output_w;
1524 asset->height = session->output_h;
1525 asset->aspect_ratio = session->aspect_w / session->aspect_h;
1526 asset->vmpeg_cmodel = BC_YUV420P;
1527 asset->vmpeg_fix_bitrate = 1;
1528 asset->vmpeg_bitrate = vid_bitrate;
1529 asset->vmpeg_quantization = 15;
1530 asset->vmpeg_iframe_distance = 15;
1531 asset->vmpeg_progressive = 0;
1532 asset->vmpeg_denoise = 0;
1533 asset->vmpeg_seq_codes = 0;
1534 asset->vmpeg_derivative = 2;
1535 asset->vmpeg_preset = 8;
1536 asset->vmpeg_field_order = 0;
1537 asset->vmpeg_pframe_distance = 0;
1539 job = new BatchRenderJob(mwindow->preferences);
1541 strcpy(&job->edl_path[0], xml_filename);
1544 sprintf(&asset->path[0],"%s/dvd.ac3", asset_dir);
1545 asset->audio_data = 1;
1546 asset->format = FILE_AC3;
1547 asset->channels = session->audio_channels;
1548 asset->sample_rate = session->sample_rate;
1550 asset->byte_order = 0;
1554 asset->ac3_bitrate = DVD_KAUDIO_RATE;
1556 job = new BatchRenderJob(mwindow->preferences);
1558 job->edl_path[0] = '@';
1559 strcpy(&job->edl_path[1], script_filename);
1560 strcpy(&job->asset->path[0], asset_dir);
1565 void CreateDVD_Thread::handle_close_event(int result)
1567 if( result ) return;
1568 mwindow->batch_render->load_defaults(mwindow->defaults);
1569 mwindow->undo->update_undo_before();
1570 KeyFrame keyframe; char data[BCTEXTLEN];
1571 if( use_deinterlace ) {
1572 sprintf(data,"<DEINTERLACE MODE=1>");
1573 keyframe.set_data(data);
1574 insert_video_plugin("Deinterlace", &keyframe);
1576 if( use_inverse_telecine ) {
1577 sprintf(data,"<IVTC FRAME_OFFSET=0 FIRST_FIELD=0 "
1578 "AUTOMATIC=1 AUTO_THRESHOLD=2.0e+00 PATTERN=2>");
1579 keyframe.set_data(data);
1580 insert_video_plugin("Inverse Telecine", &keyframe);
1583 sprintf(data,"<SCALE TYPE=1 X_FACTOR=1 Y_FACTOR=1 "
1584 "WIDTH=%d HEIGHT=%d CONSTRAIN=0>", DVD_WIDTH, DVD_HEIGHT);
1585 keyframe.set_data(data);
1586 insert_video_plugin("Scale", &keyframe);
1588 if( use_resize_tracks )
1590 if( use_histogram ) {
1592 sprintf(data, "<HISTOGRAM OUTPUT_MIN_0=0 OUTPUT_MAX_0=1 "
1593 "OUTPUT_MIN_1=0 OUTPUT_MAX_1=1 "
1594 "OUTPUT_MIN_2=0 OUTPUT_MAX_2=1 "
1595 "OUTPUT_MIN_3=0 OUTPUT_MAX_3=1 "
1596 "AUTOMATIC=0 THRESHOLD=9.0-01 PLOT=0 SPLIT=0>"
1597 "<POINTS></POINTS><POINTS></POINTS><POINTS></POINTS>"
1598 "<POINTS><POINT X=6.0e-02 Y=0>"
1599 "<POINT X=9.4e-01 Y=1></POINTS>");
1601 sprintf(data, "<HISTOGRAM AUTOMATIC=0 THRESHOLD=1.0e-01 "
1602 "PLOT=0 SPLIT=0 W=440 H=500 PARADE=0 MODE=3 "
1603 "LOW_OUTPUT_0=0 HIGH_OUTPUT_0=1 LOW_INPUT_0=0 HIGH_INPUT_0=1 GAMMA_0=1 "
1604 "LOW_OUTPUT_1=0 HIGH_OUTPUT_1=1 LOW_INPUT_1=0 HIGH_INPUT_1=1 GAMMA_1=1 "
1605 "LOW_OUTPUT_2=0 HIGH_OUTPUT_2=1 LOW_INPUT_2=0 HIGH_INPUT_2=1 GAMMA_2=1 "
1606 "LOW_OUTPUT_3=0 HIGH_OUTPUT_3=1 LOW_INPUT_3=0.06 HIGH_INPUT_3=0.94 "
1609 keyframe.set_data(data);
1610 insert_video_plugin("Histogram", &keyframe);
1612 create_dvd_jobs(&mwindow->batch_render->jobs, tmp_path, asset_title);
1613 mwindow->save_backup();
1614 mwindow->undo->update_undo_after(_("create dvd"), LOAD_ALL);
1615 mwindow->resync_guis();
1616 mwindow->batch_render->handle_close_event(0);
1617 mwindow->batch_render->start();
1620 BC_Window* CreateDVD_Thread::new_gui()
1622 memset(tmp_path,0,sizeof(tmp_path));
1623 strcpy(tmp_path,"/tmp");
1624 memset(asset_title,0,sizeof(asset_title));
1625 time_t dt; time(&dt);
1626 struct tm dtm; localtime_r(&dt, &dtm);
1627 sprintf(asset_title, "dvd_%02d%02d%02d-%02d%02d%02d",
1628 dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
1629 dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
1630 use_deinterlace = 0;
1631 use_inverse_telecine = 0;
1633 use_resize_tracks = 0;
1636 use_wide_aspect = 0;
1637 use_label_chapters = 0;
1639 int scr_x = mwindow->gui->get_screen_x(0, -1);
1640 int scr_w = mwindow->gui->get_screen_w(0, -1);
1641 int scr_h = mwindow->gui->get_screen_h(0, -1);
1642 int w = 500, h = 250;
1643 int x = scr_x + scr_w/2 - w/2, y = scr_h/2 - h/2;
1645 gui = new CreateDVD_GUI(this, x, y, w, h);
1646 gui->create_objects();
1651 CreateDVD_OK::CreateDVD_OK(CreateDVD_GUI *gui, int x, int y)
1655 set_tooltip("end setup, start batch render");
1658 CreateDVD_OK::~CreateDVD_OK()
1662 int CreateDVD_OK::button_press_event()
1664 if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
1671 int CreateDVD_OK::keypress_event()
1677 CreateDVD_Cancel::CreateDVD_Cancel(CreateDVD_GUI *gui, int x, int y)
1678 : BC_CancelButton(x, y)
1683 CreateDVD_Cancel::~CreateDVD_Cancel()
1687 int CreateDVD_Cancel::button_press_event()
1689 if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
1697 CreateDVD_DiskSpace::CreateDVD_DiskSpace(CreateDVD_GUI *gui, int x, int y)
1698 : BC_Title(x, y, "", MEDIUMFONT, GREEN)
1703 CreateDVD_DiskSpace::~CreateDVD_DiskSpace()
1707 int64_t CreateDVD_DiskSpace::tmp_path_space()
1709 const char *path = gui->tmp_path->get_text();
1710 if( access(path,R_OK+W_OK) ) return 0;
1712 if( statfs(path, &sfs) ) return 0;
1713 return (int64_t)sfs.f_bsize * sfs.f_bfree;
1716 void CreateDVD_DiskSpace::update()
1718 // gui->disk_space->set_color(get_bg_color());
1719 int64_t disk_space = tmp_path_space();
1720 int color = disk_space<gui->needed_disk_space ? RED : GREEN;
1721 static const char *suffix[] = { "", "KB", "MB", "GB", "TB", "PB" };
1723 for( int64_t space=disk_space; i<5 && (space/=1000)>0; disk_space=space, ++i );
1724 char text[BCTEXTLEN];
1725 sprintf(text, "disk space: " _LDv(3) "%s", disk_space, suffix[i]);
1726 gui->disk_space->BC_Title::update(text);
1727 gui->disk_space->set_color(color);
1730 CreateDVD_TmpPath::CreateDVD_TmpPath(CreateDVD_GUI *gui, int x, int y, int w)
1731 : BC_TextBox(x, y, w, 1, -sizeof(gui->thread->tmp_path),
1732 gui->thread->tmp_path, 1, MEDIUMFONT)
1737 CreateDVD_TmpPath::~CreateDVD_TmpPath()
1741 int CreateDVD_TmpPath::handle_event()
1743 gui->disk_space->update();
1748 CreateDVD_AssetTitle::CreateDVD_AssetTitle(CreateDVD_GUI *gui, int x, int y, int w)
1749 : BC_TextBox(x, y, w, 1, 0, gui->thread->asset_title, 1, MEDIUMFONT)
1754 CreateDVD_AssetTitle::~CreateDVD_AssetTitle()
1759 CreateDVD_Deinterlace::CreateDVD_Deinterlace(CreateDVD_GUI *gui, int x, int y)
1760 : BC_CheckBox(x, y, &gui->thread->use_deinterlace, "Deinterlace")
1765 CreateDVD_Deinterlace::~CreateDVD_Deinterlace()
1769 int CreateDVD_Deinterlace::handle_event()
1772 gui->need_inverse_telecine->set_value(0);
1773 gui->thread->use_inverse_telecine = 0;
1775 return BC_CheckBox::handle_event();
1779 CreateDVD_InverseTelecine::CreateDVD_InverseTelecine(CreateDVD_GUI *gui, int x, int y)
1780 : BC_CheckBox(x, y, &gui->thread->use_inverse_telecine, "Inverse Telecine")
1785 CreateDVD_InverseTelecine::~CreateDVD_InverseTelecine()
1789 int CreateDVD_InverseTelecine::handle_event()
1792 gui->need_deinterlace->set_value(0);
1793 gui->thread->use_deinterlace = 0;
1795 return BC_CheckBox::handle_event();
1799 CreateDVD_Scale::CreateDVD_Scale(CreateDVD_GUI *gui, int x, int y)
1800 : BC_CheckBox(x, y, &gui->thread->use_scale, "Scale")
1805 CreateDVD_Scale::~CreateDVD_Scale()
1810 CreateDVD_ResizeTracks::CreateDVD_ResizeTracks(CreateDVD_GUI *gui, int x, int y)
1811 : BC_CheckBox(x, y, &gui->thread->use_resize_tracks, "Resize Tracks")
1816 CreateDVD_ResizeTracks::~CreateDVD_ResizeTracks()
1821 CreateDVD_Histogram::CreateDVD_Histogram(CreateDVD_GUI *gui, int x, int y)
1822 : BC_CheckBox(x, y, &gui->thread->use_histogram, "Histogram")
1827 CreateDVD_Histogram::~CreateDVD_Histogram()
1831 CreateDVD_LabelChapters::CreateDVD_LabelChapters(CreateDVD_GUI *gui, int x, int y)
1832 : BC_CheckBox(x, y, &gui->thread->use_label_chapters, "Chapters at Labels")
1837 CreateDVD_LabelChapters::~CreateDVD_LabelChapters()
1841 CreateDVD_WideAudio::CreateDVD_WideAudio(CreateDVD_GUI *gui, int x, int y)
1842 : BC_CheckBox(x, y, &gui->thread->use_wide_audio, "Audio 5.1")
1847 CreateDVD_WideAudio::~CreateDVD_WideAudio()
1851 CreateDVD_WideAspect::CreateDVD_WideAspect(CreateDVD_GUI *gui, int x, int y)
1852 : BC_CheckBox(x, y, &gui->thread->use_wide_aspect, "Aspect 16x9")
1857 CreateDVD_WideAspect::~CreateDVD_WideAspect()
1864 CreateDVD_GUI::CreateDVD_GUI(CreateDVD_Thread *thread, int x, int y, int w, int h)
1865 : BC_Window(PROGRAM_NAME ": Create DVD", x, y, w, h, 50, 50, 1, 0, 1)
1867 this->thread = thread;
1868 at_x = at_y = tmp_x = tmp_y = 0;
1869 ok_x = ok_y = ok_w = ok_h = 0;
1870 cancel_x = cancel_y = cancel_w = cancel_h = 0;
1874 needed_disk_space = 15e9;
1875 need_deinterlace = 0;
1876 need_inverse_telecine = 0;
1878 need_resize_tracks = 0;
1880 need_wide_audio = 0;
1881 need_wide_aspect = 0;
1882 need_label_chapters = 0;
1887 CreateDVD_GUI::~CreateDVD_GUI()
1891 void CreateDVD_GUI::create_objects()
1893 lock_window("CreateDVD_GUI::create_objects");
1894 int pady = BC_TextBox::calculate_h(this, MEDIUMFONT, 0, 1) + 5;
1895 int padx = BC_Title::calculate_w(this, (char*)"X", MEDIUMFONT);
1896 int x = padx/2, y = pady/2;
1897 BC_Title *title = new BC_Title(x, y, "Title:", MEDIUMFONT, YELLOW);
1898 add_subwindow(title);
1899 at_x = x + title->get_w(); at_y = y;
1900 asset_title = new CreateDVD_AssetTitle(this, at_x, at_y, get_w()-at_x-10);
1901 add_subwindow(asset_title);
1902 y += title->get_h() + pady/2;
1903 title = new BC_Title(x, y, "tmp path:", MEDIUMFONT, YELLOW);
1904 add_subwindow(title);
1905 tmp_x = x + title->get_w(); tmp_y = y;
1906 tmp_path = new CreateDVD_TmpPath(this, tmp_x, tmp_y, get_w()-tmp_x-10);
1907 add_subwindow(tmp_path);
1908 y += title->get_h() + pady/2;
1909 disk_space = new CreateDVD_DiskSpace(this, x, y);
1910 add_subwindow(disk_space);
1911 disk_space->update();
1912 y += disk_space->get_h() + pady/2;
1913 need_deinterlace = new CreateDVD_Deinterlace(this, x, y);
1914 add_subwindow(need_deinterlace);
1915 int x1 = x + 150, x2 = x1 + 150;
1916 need_inverse_telecine = new CreateDVD_InverseTelecine(this, x1, y);
1917 add_subwindow(need_inverse_telecine);
1918 y += need_deinterlace->get_h() + pady/2;
1919 need_scale = new CreateDVD_Scale(this, x, y);
1920 add_subwindow(need_scale);
1921 need_wide_audio = new CreateDVD_WideAudio(this, x1, y);
1922 add_subwindow(need_wide_audio);
1923 need_resize_tracks = new CreateDVD_ResizeTracks(this, x2, y);
1924 add_subwindow(need_resize_tracks);
1925 y += need_scale->get_h() + pady/2;
1926 need_histogram = new CreateDVD_Histogram(this, x, y);
1927 add_subwindow(need_histogram);
1928 need_wide_aspect = new CreateDVD_WideAspect(this, x1, y);
1929 add_subwindow(need_wide_aspect);
1930 need_label_chapters = new CreateDVD_LabelChapters(this, x2, y);
1931 add_subwindow(need_label_chapters);
1932 ok_w = BC_OKButton::calculate_w();
1933 ok_h = BC_OKButton::calculate_h();
1935 ok_y = get_h() - ok_h - 10;
1936 ok = new CreateDVD_OK(this, ok_x, ok_y);
1938 cancel_w = BC_CancelButton::calculate_w();
1939 cancel_h = BC_CancelButton::calculate_h();
1940 cancel_x = get_w() - cancel_w - 10,
1941 cancel_y = get_h() - cancel_h - 10;
1942 cancel = new CreateDVD_Cancel(this, cancel_x, cancel_y);
1943 add_subwindow(cancel);
1948 int CreateDVD_GUI::resize_event(int w, int h)
1950 asset_title->reposition_window(at_x, at_y, get_w()-at_x-10);
1951 tmp_path->reposition_window(tmp_x, tmp_y, get_w()-tmp_x-10);
1952 ok_y = h - ok_h - 10;
1953 ok->reposition_window(ok_x, ok_y);
1954 cancel_x = w - cancel_w - 10,
1955 cancel_y = h - cancel_h - 10;
1956 cancel->reposition_window(cancel_x, cancel_y);
1960 int CreateDVD_GUI::translation_event()
1965 int CreateDVD_GUI::close_event()
1971 int CreateDVD_Thread::
1972 insert_video_plugin(const char *title, KeyFrame *default_keyframe)
1974 Tracks *tracks = mwindow->edl->tracks;
1975 for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
1976 if( vtrk->data_type != TRACK_VIDEO ) continue;
1977 if( !vtrk->record ) continue;
1978 vtrk->expand_view = 1;
1979 PluginSet *plugin_set = new PluginSet(mwindow->edl, vtrk);
1980 vtrk->plugin_set.append(plugin_set);
1981 Edits *edits = vtrk->edits;
1982 for( Edit *edit=edits->first; edit; edit=edit->next ) {
1983 plugin_set->insert_plugin(title,
1984 edit->startproject, edit->length,
1985 PLUGIN_STANDALONE, 0, default_keyframe, 0);
1992 int CreateDVD_Thread::
1995 Tracks *tracks = mwindow->edl->tracks;
1996 int max_w = 0, max_h = 0;
1997 for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
1998 if( vtrk->data_type != TRACK_VIDEO ) continue;
1999 if( !vtrk->record ) continue;
2000 Edits *edits = vtrk->edits;
2001 for( Edit *edit=edits->first; edit; edit=edit->next ) {
2002 Indexable *indexable = edit->get_source();
2003 int w = indexable->get_w();
2004 if( w > max_w ) max_w = w;
2005 int h = indexable->get_h();
2006 if( h > max_h ) max_h = h;
2009 for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
2010 if( vtrk->data_type != TRACK_VIDEO ) continue;
2011 if( !vtrk->record ) continue;
2012 vtrk->track_w = max_w;
2013 vtrk->track_h = max_h;
2018 int CreateDVD_Thread::
2021 if( !mwindow->edl ) return 1;
2022 Tracks *tracks = mwindow->edl->tracks;
2023 int max_w = 0, max_h = 0;
2024 int has_deinterlace = 0, has_scale = 0;
2025 for( Track *trk=tracks->first; trk; trk=trk->next ) {
2026 if( !trk->record ) continue;
2027 Edits *edits = trk->edits;
2028 switch( trk->data_type ) {
2030 for( Edit *edit=edits->first; edit; edit=edit->next ) {
2031 Indexable *indexable = edit->get_source();
2032 int w = indexable->get_w();
2033 if( w > max_w ) max_w = w;
2034 if( w != DVD_WIDTH ) use_scale = 1;
2035 int h = indexable->get_h();
2036 if( h > max_h ) max_h = h;
2037 if( h != DVD_HEIGHT ) use_scale = 1;
2039 for( int i=0; i<trk->plugin_set.size(); ++i ) {
2040 for(Plugin *plugin = (Plugin*)trk->plugin_set[i]->first;
2042 plugin = (Plugin*)plugin->next) {
2043 if( !strcmp(plugin->title, "Deinterlace") )
2044 has_deinterlace = 1;
2045 if( !strcmp(plugin->title, "Scale") )
2052 if( has_scale ) use_scale = 0;
2053 for( Track *trk=tracks->first; trk && !use_resize_tracks; trk=trk->next ) {
2054 if( !trk->record ) continue;
2055 switch( trk->data_type ) {
2057 if( trk->track_w != max_w ) use_resize_tracks = 1;
2058 if( trk->track_h != max_h ) use_resize_tracks = 1;
2062 if( !has_deinterlace && max_h > 2*DVD_HEIGHT ) use_deinterlace = 1;
2063 Labels *labels = mwindow->edl->labels;
2064 use_label_chapters = labels && labels->first ? 1 : 0;
2066 MWindow::create_aspect_ratio(w, h, max_w, max_h);
2067 if( w == DVD_WIDE_ASPECT_WIDTH && h == DVD_WIDE_ASPECT_HEIGHT )
2068 use_wide_aspect = 1;
2069 if( tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )