add crop plugin, add timeline bars, render setup err chks, minor tweaks
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / batchrender.C
index ae1cef938410cd79ceefa0a9592cde373f79704f..6f1129f0afcee60f51c86c9c45ae89d7327b0845 100644 (file)
 #include "file.h"
 #include "filesystem.h"
 #include "filexml.h"
+#include "indexable.h"
 #include "keyframe.h"
 #include "keys.h"
 #include "labels.h"
 #include "language.h"
+#include "localsession.h"
 #include "mainerror.h"
 #include "mainundo.h"
 #include "mainsession.h"
@@ -55,7 +57,9 @@
 #include "transportque.h"
 #include "vframe.h"
 
-// Farmed is not present if not preferences->use_renderfarm
+#include "dvdcreate.h"
+#include "bdcreate.h"
+
 int BatchRenderThread::column_widths[] = { 42, 42, 42, 222, 222, 150 };
 const char *BatchRenderThread::column_titles[] = {
        N_("Enabled"), N_("Labeled"), N_("Farmed"), N_("Output"), N_("EDL"), N_("Elapsed")
@@ -70,13 +74,14 @@ BatchRenderMenuItem::BatchRenderMenuItem(MWindow *mwindow)
 
 int BatchRenderMenuItem::handle_event()
 {
-       mwindow->batch_render->start();
+       mwindow->batch_render->start(1, 1);
        return 1;
 }
 
-
-BatchRenderJob::BatchRenderJob(Preferences *preferences, int labeled, int farmed)
+BatchRenderJob::BatchRenderJob(const char *tag,
+               Preferences *preferences, int labeled, int farmed)
 {
+       this->tag = tag;
        this->preferences = preferences;
        this->labeled = labeled;
        this->farmed = farmed >= 0 ? farmed : preferences->use_renderfarm;
@@ -86,6 +91,11 @@ BatchRenderJob::BatchRenderJob(Preferences *preferences, int labeled, int farmed
        elapsed = 0;
 }
 
+BatchRenderJob::BatchRenderJob(Preferences *preferences, int labeled, int farmed)
+ : BatchRenderJob("JOB", preferences, labeled, farmed)
+{
+}
+
 BatchRenderJob::~BatchRenderJob()
 {
        asset->Garbage::remove_user();
@@ -101,13 +111,20 @@ void BatchRenderJob::copy_from(BatchRenderJob *src)
        elapsed = 0;
 }
 
+BatchRenderJob *BatchRenderJob::copy()
+{
+       BatchRenderJob *t = new BatchRenderJob(tag, preferences, labeled, farmed);
+       t->copy_from(this);
+       return t;
+}
+
 void BatchRenderJob::load(FileXML *file)
 {
        int result = 0;
 
        enabled = file->tag.get_property("ENABLED", enabled);
        farmed = file->tag.get_property("FARMED", farmed);
-       labeled = file->tag.get_property("STRATEGY", labeled);
+       labeled = file->tag.get_property("LABELED", labeled);
        edl_path[0] = 0;
        file->tag.get_property("EDL_PATH", edl_path);
        elapsed = file->tag.get_property("ELAPSED", elapsed);
@@ -130,6 +147,8 @@ void BatchRenderJob::load(FileXML *file)
 
 void BatchRenderJob::save(FileXML *file)
 {
+       char end_tag[BCSTRLEN];  end_tag[0] = '/';
+       strcpy(&end_tag[1], file->tag.get_title());
        file->tag.set_property("ENABLED", enabled);
        file->tag.set_property("FARMED", farmed);
        file->tag.set_property("LABELED", labeled);
@@ -148,16 +167,19 @@ void BatchRenderJob::save(FileXML *file)
        defaults.save_string(string);
        file->append_text(string);
        free(string);
-       file->tag.set_title("/JOB");
+       file->tag.set_title(end_tag);
        file->append_tag();
        file->append_newline();
 }
 
+char *BatchRenderJob::create_script(EDL *edl, ArrayList<Indexable *> *idxbls)
+{
+       return 0;
+}
+
 int BatchRenderJob::get_strategy()
 {
-// if set, overrides farmed, labeled
-       int use_renderfarm = farmed && preferences->use_renderfarm ? 1 : 0;
-       return Render::get_strategy(use_renderfarm, labeled);
+       return Render::get_strategy(farmed, labeled);
 }
 
 
@@ -174,21 +196,8 @@ BatchRenderThread::BatchRenderThread(MWindow *mwindow)
        warn = 1;
        render = 0;
        batch_path[0] = 0;
-}
-
-BatchRenderThread::BatchRenderThread()
- : BC_DialogThread()
-{
-       mwindow = 0;
-       current_job = 0;
-       rendering_job = -1;
-       is_rendering = 0;
-       default_job = 0;
-       boot_defaults = 0;
-       preferences = 0;
-       warn = 1;
-       render = 0;
-       batch_path[0] = 0;
+       do_farmed = 0;
+       do_labeled = 0;
 }
 
 BatchRenderThread::~BatchRenderThread()
@@ -196,6 +205,7 @@ BatchRenderThread::~BatchRenderThread()
        close_window();
        delete boot_defaults;
        delete preferences;
+       delete default_job;
        delete render;
 }
 
@@ -211,6 +221,13 @@ void BatchRenderThread::reset(const char *path)
        jobs.remove_all_objects();
 }
 
+void BatchRenderThread::start(int do_farmed, int do_labeled)
+{
+       this->do_farmed = do_farmed;
+       this->do_labeled = do_labeled;
+       BC_DialogThread::start();
+}
+
 void BatchRenderThread::handle_close_event(int result)
 {
 // Save settings
@@ -223,7 +240,7 @@ BC_Window* BatchRenderThread::new_gui()
 {
        current_start = 0.0;
        current_end = 0.0;
-       default_job = new BatchRenderJob(mwindow->preferences);
+       default_job = new BatchRenderJob(mwindow->preferences, 0, -1);
        load_jobs(batch_path, mwindow->preferences);
        load_defaults(mwindow->defaults);
        this->gui = new BatchRenderGUI(mwindow, this,
@@ -250,7 +267,17 @@ void BatchRenderThread::load_jobs(char *path, Preferences *preferences)
                                warn = file.tag.get_property("WARN", 1);
                        }
                        else if( file.tag.title_is("JOB") ) {
-                               BatchRenderJob *job =  new BatchRenderJob(preferences);
+                               BatchRenderJob *job =  new BatchRenderJob(preferences, 0,0);
+                               jobs.append(job);
+                               job->load(&file);
+                       }
+                       else if( file.tag.title_is("DVD_JOB") ) {
+                               DVD_BatchRenderJob *job =  new DVD_BatchRenderJob(preferences, 0,0,0,0);
+                               jobs.append(job);
+                               job->load(&file);
+                       }
+                       else if( file.tag.title_is("BD_JOB") ) {
+                               BD_BatchRenderJob *job =  new BD_BatchRenderJob(preferences, 0,0);
                                jobs.append(job);
                                job->load(&file);
                        }
@@ -267,8 +294,8 @@ void BatchRenderThread::save_jobs(char *path)
        file.append_newline();
 
        for( int i = 0; i < jobs.total; i++ ) {
-               file.tag.set_title("JOB");
-               jobs.values[i]->save(&file);
+               file.tag.set_title(jobs[i]->tag);
+               jobs[i]->save(&file);
        }
        file.tag.set_title("/JOBS");
        file.append_tag();
@@ -322,8 +349,7 @@ char* BatchRenderThread::create_path(char *string)
 
 void BatchRenderThread::new_job()
 {
-       BatchRenderJob *result = new BatchRenderJob(mwindow->preferences);
-       result->copy_from(get_current_job());
+       BatchRenderJob *result = get_current_job()->copy();
        jobs.append(result);
        current_job = jobs.total - 1;
        gui->create_list(1);
@@ -383,38 +409,75 @@ char* BatchRenderThread::get_current_edl()
        return get_current_job()->edl_path;
 }
 
+int BatchRenderThread::test_errmsg(BatchRenderWarnJobs &err_jobs, const char *msg, int *warn)
+{
+       int count = err_jobs.size();
+       if( !count ) return 0;
+       fprintf(stderr, msg, count);
+       char string[BCTEXTLEN], *sp = string, *ep = sp+sizeof(string)-1;
+       sp += snprintf(sp,ep-sp, msg,count);
+       for( int i=0; i<count; ++i ) {
+               int no = err_jobs[i].no;
+               const char *path = err_jobs[i].path;
+               fprintf(stderr, "%d: %s\n", no, path);
+               sp += snprintf(sp,ep-sp, "%d: %s\n", no, path);
+       }
+       sp += snprintf(sp,ep-sp, _("press cancel to abandon batch render"));
+       mwindow->show_warning(warn, string);
+       if( mwindow->wait_warning() ) {
+               gui->button_enable();
+       }
+       return 1;
+}
 
 // Test EDL files for existence
 int BatchRenderThread::test_edl_files()
 {
-       int not_equiv = 0, ret = 0;
+       int ret = 0;
        const char *path = 0;
+       BatchRenderWarnJobs not_equiv;
+       BatchRenderWarnJobs empty_jobs;
+       BatchRenderWarnJobs no_labels;
+       BatchRenderWarnJobs no_rendering;
 
        for( int i=0; !ret && i<jobs.size(); ++i ) {
                if( !jobs.values[i]->enabled ) continue;
-               path = jobs.values[i]->edl_path;
+               path = jobs[i]->edl_path;
                int is_script = *path == '@' ? 1 : 0;
                if( is_script ) ++path;
                FILE *fp = fopen(path, "r");
                if( fp ) {
-                       if( warn && mwindow && !is_script ) {
-                               fseek(fp, 0, SEEK_END);
-                               int64_t sz = ftell(fp);
-                               fseek(fp, 0, SEEK_SET);
-                               char *bfr = new char[sz+1];
-                               int64_t len = fread(bfr, 1, sz+1, fp);
-                               if( len == sz ) {
-                                       FileXML file;
-                                       XMLBuffer data(bfr, len, 0);
-                                       file.set_shared_input(&data);
+                       if( mwindow && !is_script ) {
+                               char *bfr = 0;  size_t sz = 0;
+                               struct stat st;
+                               if( !fstat(fileno(fp), &st) ) {
+                                       sz = st.st_size;
+                                       bfr = new char[sz+1];
+                                       if( fread(bfr, 1, sz+1, fp) != sz )
+                                               ret = 1;
+                                       else
+                                               bfr[sz] = 0;
+                               }
+                               if( !ret ) {
                                        EDL *edl = new EDL; edl->create_objects();
-                                       edl->load_xml(&file, LOAD_ALL);
+                                       XMLBuffer data(bfr, sz, 0);
+                                       { FileXML file;
+                                       file.set_shared_input(&data);
+                                       edl->load_xml(&file, LOAD_ALL); }
                                        double pos = edl->equivalent_output(mwindow->edl);
-                                       if( pos >= 0 ) ++not_equiv;
+                                       if( pos >= 0 )
+                                               not_equiv.add(i+1, path);
+                                       double length = edl->tracks->total_playable_length();
+                                       double start = edl->local_session->get_selectionstart(1);
+                                       if( start >= length )
+                                               empty_jobs.add(i+1, path);
+                                       if( jobs[i]->labeled && !edl->labels->first)
+                                               no_labels.add(i+1,path);
+                                       Asset *asset = jobs[i]->asset;
+                                       if( !asset->audio_data && !asset->video_data )
+                                               no_rendering.add(i+1,path);
                                        edl->remove_user();
                                }
-                               else
-                                       ret = 1;
                                delete [] bfr;
                        }
                        fclose(fp);
@@ -438,21 +501,21 @@ int BatchRenderThread::test_edl_files()
                        fprintf(stderr, "%s", string);
                }
                is_rendering = 0;
-       }
-       else if( warn && mwindow && not_equiv > 0 ) {
-               fprintf(stderr, _("%d job EDLs do not match session edl\n"), not_equiv);
-               char string[BCTEXTLEN], *sp = string;
-               sp += sprintf(sp, _("%d job EDLs do not match session edl\n"),not_equiv);
-               sp += sprintf(sp, _("press cancel to abandon batch render"));
-               mwindow->show_warning(&warn, string);
-               if( mwindow->wait_warning() ) {
-                       gui->button_enable();
-                       is_rendering = 0;
-                       ret = 1;
-               }
-               gui->warning->update(warn);
+               ret = 1;
        }
 
+       if( !ret && warn && mwindow ) {
+               ret = test_errmsg(not_equiv, _("%d job EDLs do not match session edl\n"), &warn);
+               if( !warn ) gui->warning->update(0);
+       }
+       if( !ret && mwindow )
+               ret = test_errmsg(empty_jobs, _("%d job EDLs begin position beyond end of media\n"), 0);
+       if( !ret && mwindow )
+               ret = test_errmsg(no_rendering, _("%d job EDLs no audio or video in render asset format\n"), 0);
+       if( !ret && mwindow )
+               ret = test_errmsg(no_labels, _("%d job EDLs render file per label and no labels\n"), 0);
+       if( ret )
+               is_rendering = 0;
        return ret;
 }
 
@@ -478,17 +541,13 @@ void BatchRenderThread::calculate_dest_paths(ArrayList<char*> *paths,
                        command->playback_range_adjust_inout();
 
 // Create test packages
-                       packages->create_packages(mwindow,
-                               command->get_edl(),
-                               preferences,
-                               job->get_strategy(),
-                               job->asset,
-                               command->start_position,
-                               command->end_position,
-                               0);
+                       int result = packages->create_packages(mwindow, command->get_edl(),
+                               preferences, job->get_strategy(), job->asset,
+                               command->start_position, command->end_position, 0);
+                       if( !result )
+                               packages->get_package_paths(paths);
 
 // Append output paths allocated to total
-                       packages->get_package_paths(paths);
 
 // Delete package harness
                        delete packages;
@@ -510,6 +569,7 @@ void BatchRenderThread::start_rendering(char *config_path,
 //PRINT_TRACE
 // Initialize stuff which MWindow does.
        signals->initialize("/tmp/cinelerra_batch%d.dmp");
+       boot_defaults = 0;
        MWindow::init_defaults(boot_defaults, config_path);
        load_defaults(boot_defaults);
        preferences = new Preferences;
@@ -689,7 +749,7 @@ void BatchRenderGUI::create_objects()
 
        int x = mwindow->theme->batchrender_x1;
        int y = 5;
-       int x1 = x, x2 = get_w()/2 + 10; // mwindow->theme->batchrender_x2;
+       int x1 = x, x2 = get_w()/2 + 30; // mwindow->theme->batchrender_x2;
        int y1 = 5, y2 = 5;
 
 // output file
@@ -697,16 +757,21 @@ void BatchRenderGUI::create_objects()
        y1 += output_path_title->get_h() + mwindow->theme->widget_border;
 
        format_tools = new BatchFormat(mwindow, this, thread->get_current_asset());
-       format_tools->set_w(get_w() / 2);
+       format_tools->set_w(x2 - 40);
        BatchRenderJob *current_job = thread->get_current_job();
        format_tools->create_objects(x1, y1, 1, 1, 1, 1, 0, 1, 0, 0,
-                       &current_job->labeled, 0);
-       if( mwindow->preferences->use_renderfarm ) {
+                       thread->do_labeled ? &current_job->labeled : 0, 0);
+       if( thread->do_labeled < 0 )
+               format_tools->labeled_files->disable();
+       if( thread->do_farmed ) {
                use_renderfarm = new BatchRenderUseFarm(thread, x1, y1,
                        &current_job->farmed);
                add_subwindow(use_renderfarm);
                y1 += use_renderfarm->get_h() + 10;
+               if( thread->do_farmed < 0 )
+                       use_renderfarm->disable();
        }
+
 // input EDL
        add_subwindow(edl_path_title = new BC_Title(x2, y2, _("EDL Path:")));
        y2 += edl_path_title->get_h() + mwindow->theme->widget_border;
@@ -791,7 +856,7 @@ int BatchRenderGUI::resize_event(int w, int h)
        output_path_title->reposition_window(x1, y1);
        y1 += output_path_title->get_h() + mwindow->theme->widget_border;
        format_tools->reposition_window(x1, y1);
-       if( use_renderfarm )
+       if( thread->do_farmed )
                use_renderfarm->reposition_window(x1, y1);
 // input EDL
        x = x2, y = y2;
@@ -863,9 +928,11 @@ void BatchRenderGUI::create_list(int update_widget)
        list_columns = 0;
        list_titles[list_columns] = _(column_titles[ENABLED_COL]);
        list_width[list_columns++] = thread->list_width[ENABLED_COL];
-       list_titles[list_columns] = _(column_titles[LABELED_COL]);
-       list_width[list_columns++] = thread->list_width[LABELED_COL];
-       if( mwindow->preferences->use_renderfarm ) {
+       if( thread->do_labeled > 0 ) {
+               list_titles[list_columns] = _(column_titles[LABELED_COL]);
+               list_width[list_columns++] = thread->list_width[LABELED_COL];
+       }
+       if( thread->do_farmed > 0 ) {
                list_titles[list_columns] = _(column_titles[FARMED_COL]);
                list_width[list_columns++] = thread->list_width[FARMED_COL];
        }
@@ -880,23 +947,24 @@ void BatchRenderGUI::create_list(int update_widget)
                BatchRenderJob *job = thread->jobs.values[i];
                char string[BCTEXTLEN];
                BC_ListBoxItem *enabled = new BC_ListBoxItem(job->enabled ? "X" : " ");
-               BC_ListBoxItem *labeled = new BC_ListBoxItem(job->labeled ? "X" : " ");
-               BC_ListBoxItem *farmed  = !mwindow->preferences->use_renderfarm ? 0 :
-                       new BC_ListBoxItem(job->farmed  ? "X" : " ");
+               BC_ListBoxItem *labeled = thread->do_labeled > 0 ?
+                       new BC_ListBoxItem(job->labeled ? "X" : " ") : 0;
+               BC_ListBoxItem *farmed  = thread->do_farmed > 0 ?
+                       new BC_ListBoxItem(job->farmed  ? "X" : " ") : 0;
                BC_ListBoxItem *out_path = new BC_ListBoxItem(job->asset->path);
                BC_ListBoxItem *edl_path = new BC_ListBoxItem(job->edl_path);
                BC_ListBoxItem *elapsed = new BC_ListBoxItem(!job->elapsed ? _("Unknown") :
                        Units::totext(string, job->elapsed, TIME_HMS2));
                int col = 0;
                list_items[col++].append(enabled);
-               list_items[col++].append(labeled);
+               if( labeled ) list_items[col++].append(labeled);
                if( farmed ) list_items[col++].append(farmed);
                list_items[col++].append(out_path);
                list_items[col++].append(edl_path);
                list_items[col].append(elapsed);
                if( i == thread->current_job ) {
                        enabled->set_selected(1);
-                       labeled->set_selected(1);
+                       if( labeled ) labeled->set_selected(1);
                        if( farmed ) farmed->set_selected(1);
                        out_path->set_selected(1);
                        edl_path->set_selected(1);
@@ -904,7 +972,7 @@ void BatchRenderGUI::create_list(int update_widget)
                }
                if( i == thread->rendering_job ) {
                        enabled->set_color(RED);
-                       labeled->set_color(RED);
+                       if( labeled ) labeled->set_color(RED);
                        if( farmed ) farmed->set_color(RED);
                        out_path->set_color(RED);
                        edl_path->set_color(RED);
@@ -922,8 +990,8 @@ void BatchRenderGUI::create_list(int update_widget)
 void BatchRenderGUI::change_job()
 {
        BatchRenderJob *job = thread->get_current_job();
-       format_tools->update(job->asset, &job->labeled);
-       if( use_renderfarm ) use_renderfarm->update(&job->farmed);
+       format_tools->update(job->asset, thread->do_labeled ? &job->labeled : 0);
+       if( thread->do_farmed ) use_renderfarm->update(&job->farmed);
        edl_path_text->update(job->edl_path);
 }
 
@@ -1046,7 +1114,9 @@ void BatchRenderSaveList::run()
        int result2 = filewindow.run_window();
        if( !result2 ) {
                strcpy(thread->batch_path, filewindow.get_submitted_path());
+               thread->gui->lock_window("BatchRenderSaveList::run");
                thread->gui->batch_path->update(thread->batch_path);
+               thread->gui->unlock_window();
                thread->mwindow->defaults->update("DEFAULT_BATCHLOADPATH", thread->batch_path);
                thread->save_jobs(thread->batch_path);
        }
@@ -1195,9 +1265,10 @@ int BatchRenderList::selection_changed()
        int col_x = 0, changed = 1;
        if( cursor_x < (col_x += thread->list_width[ENABLED_COL]) )
                job->enabled = !job->enabled;
-       else if( cursor_x < (col_x += thread->list_width[LABELED_COL]) )
+       else if( thread->do_labeled > 0 &&
+                cursor_x < (col_x += thread->list_width[LABELED_COL]) )
                job->labeled = job->edl_path[0] != '@' ? !job->labeled : 0;
-       else if( thread->gui->use_renderfarm &&
+       else if( thread->do_farmed > 0 &&
                 cursor_x < (col_x += thread->list_width[FARMED_COL]) )
                job->farmed = job->edl_path[0] != '@' ? !job->farmed : 0;
        else
@@ -1213,8 +1284,9 @@ int BatchRenderList::column_resize_event()
 {
        int col = 0;
        thread->list_width[ENABLED_COL] = get_column_width(col++);
-       thread->list_width[LABELED_COL] = get_column_width(col++);
-       if( thread->gui->use_renderfarm )
+       if( thread->do_labeled > 0 )
+               thread->list_width[LABELED_COL] = get_column_width(col++);
+       if( thread->do_farmed > 0 )
                thread->list_width[FARMED_COL] = get_column_width(col++);
        thread->list_width[OUTPUT_COL] = get_column_width(col++);
        thread->list_width[EDL_COL] = get_column_width(col++);