X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fmwindow.C;h=2918e23e63e59e4035bb86e2b07059ea0536fd2e;hp=c57c2ecf492e3943f0a7da3a0e5fc299f9a27685;hb=HEAD;hpb=b4017f68039ef7e31eedee4a27580a28bee36fc5 diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index c57c2ecf..1291b992 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -1,6 +1,7 @@ /* * CINELERRA * Copyright (C) 1997-2014 Adam Williams + * Copyright (C) 2003-2016 Cinelerra CV contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -283,8 +284,10 @@ MWindow::~MWindow() delete convert_render; convert_render = 0; delete render; render = 0; delete mixers_align; mixers_align = 0; +#ifdef HAVE_COMMERCIALS commit_commercial(); if( commercials && !commercials->remove_user() ) commercials = 0; +#endif close_mixers(); if( speed_edl ) { speed_edl->remove_user(); speed_edl = 0; } // Save defaults for open plugins @@ -296,6 +299,7 @@ MWindow::~MWindow() plugin_gui_lock->unlock(); hide_keyframe_guis(); clean_indexes(); + clean_backups(); save_defaults(); // Give up and go to a movie // cant run valgrind if this is used @@ -555,21 +559,46 @@ void MWindow::get_plugin_path(char *path, const char *plug_dir, const char *fs_p delete [] base_path; } -int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_dir) +/** +* @brief Load plugins according to an index file. +* +* @details Builds an ArrayList of plugin servers only if there is no +* mismatch for file layout version, index identifier, or timestamp of +* the built-in plugins. If OK, add the plugin servers to the global list. +* +* @note If an error is returned the index file needs to be rebuilt, and +* then this function must be called again. +* There are two types of index files, with the same layout internally. +* One called "Cinelerra_plugins" for built-ins, ffmpeg and lv2 . +* The other type "ladspa_plugins.index_id" where index_id is either the +* path or the $CIN_BUILD identifier if the path is from the running +* AppImage itself. If there are multiple ladspa directories in the +* path, there will be multiple index files. +* +* @return -1 if file no open, 0 if OK, 1 if error. +*/ +int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_dir, const char *index_id) { if( !fp ) return -1; + struct stat st; + fstat (fileno(fp), &st); // don't bother if the file has just been created. + if( st.st_size < 4 ) return 1; + // load index fseek(fp, 0, SEEK_SET); int ret = 0; char index_line[BCTEXTLEN]; - int index_version = -1, len = strlen(plugin_dir); + int index_version = -1, len = strlen(index_id); if( !fgets(index_line, BCTEXTLEN, fp) || sscanf(index_line, "%d", &index_version) != 1 || index_version != PLUGIN_FILE_VERSION || !fgets(index_line, BCTEXTLEN, fp) || (int)strlen(index_line)-1 != len || index_line[len] != '\n' || - strncmp(index_line, plugin_dir, len) != 0 ) ret = 1; - + strncmp(index_line, index_id, len) != 0 ) { +// printf("index file mismatch, version %d, index id length %d, expected id %s, file id %s\n", index_version, len, index_id, index_line); + ret = 1; + } + ArrayList plugins; while( !ret && !feof(fp) && fgets(index_line, BCTEXTLEN, fp) ) { if( index_line[0] == ';' ) continue; @@ -578,6 +607,7 @@ int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_di char path[BCTEXTLEN], title[BCTEXTLEN]; int64_t mtime = 0; if( PluginServer::scan_table(index_line, type, path, title, mtime) ) { +// printf("PluginServer::scan_table failed for %s\n", index_line); ret = 1; continue; } PluginServer *server = 0; @@ -588,6 +618,7 @@ int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_di char plugin_path[BCTEXTLEN]; struct stat st; sprintf(plugin_path, "%s/%s", plugin_dir, path); if( stat(plugin_path, &st) || st.st_mtime != mtime ) { +// printf("Plugin %s index time %ld, file time %ld\n", plugin_path, mtime, st.st_mtime); ret = 1; continue; } server = new PluginServer(mwindow, plugin_path, type); @@ -604,6 +635,7 @@ int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_di // Create plugin server from index entry server->set_title(title); if( server->read_table(index_line) ) { +// printf("server->read_table failed for title %s, %s\n", title, index_line); ret = 1; continue; } } @@ -643,16 +675,27 @@ int MWindow::check_plugin_index(ArrayList &plugins, return 0; } - +/** +* @brief Load built-in and LV2 plugins as specified in index file, +* rebuild the index file if needed. +* @param[in] mwindow: GUI class pointer, will be NULL for batch +* rendering or renderfarm client. +* @param[in] preferences: Information from cinelerra_rc file. +*/ int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences) { if( !plugindb ) plugindb = new ArrayList; init_ffmpeg(); - char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN]; + char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN], index_id[BCTEXTLEN]; create_defaults_path(index_path, PLUGIN_FILE); char *plugin_dir = FileSystem::basepath(preferences->plugin_dir); strcpy(plugin_path, plugin_dir); delete [] plugin_dir; + // index_id is 2nd line of the index file, normally full plugin path, + // but fixed value if AppImage because the path changes on each run. + // And if the second line does not match on the next run the index is rebuilt. + if( getenv("APPDIR") && getenv("CINGG_BUILD")) strcpy(index_id, getenv("CINGG_BUILD")); + else strcpy(index_id, plugin_path); FILE *fp = fopen(index_path,"a+"); if( !fp ) { fprintf(stderr,_("MWindow::init_plugins: " @@ -662,19 +705,19 @@ int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences) int fd = fileno(fp), ret = -1; if( !flock(fd, LOCK_EX) ) { fseek(fp, 0, SEEK_SET); - ret = load_plugin_index(mwindow, fp, plugin_path); + ret = load_plugin_index(mwindow, fp, plugin_path, index_id); } if( ret > 0 ) { ftruncate(fd, 0); fseek(fp, 0, SEEK_SET); - printf("init plugin index: %s\n", plugin_path); + printf("build plugin index for: %s\n", plugin_path); fprintf(fp, "%d\n", PLUGIN_FILE_VERSION); - fprintf(fp, "%s\n", plugin_path); + fprintf(fp, "%s\n", index_id); init_plugin_index(mwindow, preferences, fp, plugin_path); init_ffmpeg_index(mwindow, preferences, fp); init_lv2_index(mwindow, preferences, fp); fseek(fp, 0, SEEK_SET); - ret = load_plugin_index(mwindow, fp, plugin_path); + ret = load_plugin_index(mwindow, fp, plugin_path, index_id); } if( ret ) { fprintf(stderr,_("MWindow::init_plugins: " @@ -685,26 +728,42 @@ int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences) return ret; } +/** +* @brief Load ladspa plugins as specified in index files, for each ladspa +* directory keep a separate index file. Rebuild index file(s) if needed. +* @param[in] mwindow: GUI class pointer, will be NULL for batch +* rendering or renderfarm client. +* @param[in] preferences: Information from cinelerra_rc file. +*/ int MWindow::init_ladspa_plugins(MWindow *mwindow, Preferences *preferences) { #ifdef HAVE_LADSPA char *path = getenv("LADSPA_PATH"); + char *appdir = getenv("APPDIR"); char ladspa_path[BCTEXTLEN]; - if( !path ) { + if( !path ) { // if no env var, use CinGG's own ladspa dir strncpy(ladspa_path, File::get_ladspa_path(), sizeof(ladspa_path)); path = ladspa_path; } for( int len=0; *path; path+=len ) { char *cp = strchr(path,':'); len = !cp ? strlen(path) : cp-path; - char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN]; + char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN], index_id[BCTEXTLEN]; memcpy(plugin_path, path, len); plugin_path[len] = 0; if( cp ) ++len; char *plugin_dir = FileSystem::basepath(plugin_path); strcpy(plugin_path, plugin_dir); delete [] plugin_dir; create_defaults_path(index_path, LADSPA_FILE); cp = index_path + strlen(index_path); - for( char *bp=plugin_path; *bp!=0; ++bp ) + // If the first part of the plugin_path matches the APPDIR, we are + // referring to CinGG's ladspa, replace the path by a fixed ID. APPDIR + // only exists if we are running as AppImage (with variable mount points). + if( appdir && strncmp(plugin_path, appdir, strlen(appdir)) == 0 ) + strcpy(index_id, getenv("CINGG_BUILD")); + else strcpy(index_id, plugin_path); + + // Concatenate the path, replacing '/' with '_'. + for( char *bp=index_id; *bp!=0; ++bp ) *cp++ = *bp=='/' ? '_' : *bp; *cp = 0; FILE *fp = fopen(index_path,"a+"); @@ -716,14 +775,17 @@ int MWindow::init_ladspa_plugins(MWindow *mwindow, Preferences *preferences) int fd = fileno(fp), ret = -1; if( !flock(fd, LOCK_EX) ) { fseek(fp, 0, SEEK_SET); - ret = load_plugin_index(mwindow, fp, plugin_path); + ret = load_plugin_index(mwindow, fp, plugin_path, index_id); } if( ret > 0 ) { ftruncate(fd, 0); fseek(fp, 0, SEEK_SET); - init_ladspa_index(mwindow, preferences, fp, plugin_path); + printf("build ladspa plugin index for: %s\n", plugin_path); + fprintf(fp, "%d\n", PLUGIN_FILE_VERSION); + fprintf(fp, "%s\n", index_id); + init_plugin_index(mwindow, preferences, fp, plugin_path); fseek(fp, 0, SEEK_SET); - ret = load_plugin_index(mwindow, fp, plugin_path); + ret = load_plugin_index(mwindow, fp, plugin_path, index_id); } if( ret ) { fprintf(stderr,_("MWindow::init_ladspa_plugins: " @@ -765,7 +827,7 @@ void MWindow::scan_plugin_index(MWindow *mwindow, Preferences *preferences, FILE char fs_path[BCTEXTLEN], path[BCTEXTLEN]; get_plugin_path(fs_path, 0, fs.dir_list[i]->path); get_plugin_path(path, plug_dir, fs_path); - if( fs.is_dir(fs_path) ) { + if( fs.is_dir(fs_path) ) { // recursively scan child directory scan_plugin_index(mwindow, preferences, fp, plug_dir, path, idx); continue; } @@ -984,6 +1046,58 @@ void MWindow::init_preferences() YUV::yuv.yuv_set_colors(preferences->yuv_color_space, preferences->yuv_color_range); } +void MWindow::clean_backups() +{ + FileSystem fs; + int total_excess; + long oldest = 0; + int oldest_item = -1; + char string[BCTEXTLEN]; + +// Delete extra backups + fs.set_filter("backup*.prev_*"); + fs.complete_path(preferences->index_directory); + fs.update(preferences->index_directory); + + // set to 50 for now + // total_excess = fs.dir_list.total - preferences->index_count; + total_excess = fs.dir_list.total - 50; + printf("Total excess of backups: %i \n", total_excess); + +//printf("MWindow::clean_backups 1 %d\n", fs.dir_list.total); + + while(total_excess > 0) + { +// Get oldest + for(int i = 0; i < fs.dir_list.total; i++) + { + fs.join_names(string, preferences->index_directory, fs.dir_list[i]->name); + + if(i == 0 || fs.get_date(string) <= oldest) + { + oldest = fs.get_date(string); + oldest_item = i; + } + } + + if(oldest_item >= 0) + { +// Remove backup file + fs.join_names(string, + preferences->index_directory, + fs.dir_list[oldest_item]->name); +//printf("MWindow::clean_backups 1 %s\n", string); + if(remove(string)) + perror("delete_backups"); + delete fs.dir_list[oldest_item]; + fs.dir_list.remove_number(oldest_item); + + } + + total_excess--; + } +} + void MWindow::clean_indexes() { FileSystem fs; @@ -1489,6 +1603,7 @@ void MWindow::tile_mixers(int x1, int y1, int x2, int y2) if( x1 > x2 ) { int t = x1; x1 = x2; x2 = t; } if( y1 > y2 ) { int t = y1; y1 = y2; y2 = t; } } + int ow = edl->session->output_w, oh = edl->session->output_h; int nz = 0; for( int i=0; iget_root_w(0), rh = gui->get_root_h(0); - if( x1 < 0 ) x1 = 0; - if( y1 < 0 ) y1 = 0; - if( x2 > rw ) x2 = rw; - if( y2 > rh ) y2 = rh; - int dx = x2 - x1, dy = y2 - y1; - int zw = dx / zn; int lt = BC_DisplayInfo::get_left_border(); int top = BC_DisplayInfo::get_top_border(); int bw = lt + BC_DisplayInfo::get_right_border(); // borders int bh = top + BC_DisplayInfo::get_bottom_border(); - int zx = 0, zy = 0; // window origins int mw = xS(10+10), mh = yS(10+10); // canvas margins - int rsz = 0, n = 0, dz = 0; - int ow = edl->session->output_w, oh = edl->session->output_h; + int dx = x2 - x1, dy = y2 - y1; + int64_t sz = dx * dy, best_r = sz; + int bx = 1, by = nz; + for( int nx=1; nx<=nz; ++nx ) { + int ny = ceil((double)nz / nx); + int zw = dx / nx; + int ww = zw - bw; + int hh = (ww - mw) * oh / ow + mh; + int zh = hh + bh; + int64_t za = zw*nx * zh*ny; + int64_t r = sz - za; + if( r < 0 ) continue; + if( r >= best_r ) continue; + best_r = r; + bx = nx; by = ny; + } + for( int ny=1; ny<=nz; ++ny ) { + int nx = ceil((double)nz / ny); + int zh = dy / ny; + int hh = zh - bh; + int ww = (hh - mh) * ow / oh + mw; + int zw = ww + bw; + int64_t za = zw*nx * zh*ny; + int64_t r = sz - za; + if( r < 0 ) continue; + if( r >= best_r ) continue; + best_r = r; + bx = nx; by = ny; + } + int zw, zh, ww, hh; + if( bx < by ) { + zh = dy / by; + hh = zh - bh; + ww = (hh - mh) * ow / oh + mw; + zw = ww + bw; + } + else { + zw = dx / bx; + ww = zw - bw; + hh = (ww - mw) * oh / ow + mh; + zh = hh + bh; + } + + int zx = 0, zy = 0; // window origins + int n = 0; for( int i=0; iidx < 0 ) continue; - int ww = zw - bw, hh = (ww - mw) * oh / ow + mh, zh = hh + bh; - if( rsz < hh ) rsz = hh; int xx = zx + x1, yy = zy + y1; int mx = x2 - zw, my = y2 - zh; if( xx > mx ) xx = mx; if( yy > my ) yy = my; - xx += lt + xS(dz); yy += top + yS(dz); zwindow->reposition(xx,yy, ww,hh); if( zwindow->running() ) { ZWindowGUI *gui = (ZWindowGUI *)zwindow->get_gui(); @@ -1529,11 +1675,9 @@ void MWindow::tile_mixers(int x1, int y1, int x2, int y2) gui->BC_WindowBase::reposition_window(xx,yy, ww,hh); gui->unlock_window(); } - if( ++n >= zn ) { - n = 0; rsz += bh; - if( (zy += rsz) > (dy - rsz) ) dz += 10; - rsz = 0; - zx = 0; + if( ++n >= bx ) { + zx = 0; zy += zh; + n = 0; } else zx += zw; @@ -2077,6 +2221,13 @@ if(debug) printf("MWindow::load_filenames %d\n", __LINE__); } result = 0; break; } +// File is a list and size of listed files don't match + case FILE_SIZE_DONT_MATCH: { + eprintf(_("File sizes don't match")); + sprintf(string, _("File sizes don't match")); + gui->show_message(string, theme->message_error); + gui->update_default_message(); + break; } case FILE_NOT_FOUND: { eprintf(_("Failed to open %s"), new_asset->path); @@ -2967,6 +3118,25 @@ void MWindow::show_vwindow(int raise) gui->mainmenu->show_vwindow->set_checked(1); } + +void MWindow::hide_vwindow(int raise) +{ + session->show_vwindow = 0; + int total_running = 0; + + for(int j = 0; j < vwindows.size(); j++) { + VWindow *vwindow = vwindows[j]; + if( !vwindow->is_running() ) continue; + total_running++; + if( !raise && !vwindow->gui->is_hidden() ) continue; + vwindow->gui->lock_window("MWindow::show_vwindow"); + vwindow->gui->hide_window(0); + vwindow->gui->unlock_window(); + } + gui->mainmenu->show_vwindow->set_checked(0); +} + + void MWindow::show_awindow() { session->show_awindow = 1; @@ -2978,6 +3148,17 @@ void MWindow::show_awindow() gui->mainmenu->show_awindow->set_checked(1); } +void MWindow::hide_awindow() +{ + session->show_awindow = 0; + + awindow->gui->lock_window("MWindow::show_awindow"); + awindow->gui->hide_window(); + awindow->gui->unlock_window(); + gui->mainmenu->show_awindow->set_checked(0); +} + + char *MWindow::get_cwindow_display() { char *x11_host = screens < 2 || session->window_config == 0 ? @@ -2993,6 +3174,18 @@ void MWindow::show_cwindow() gui->mainmenu->show_cwindow->set_checked(1); } + +void MWindow::hide_cwindow() +{ + session->show_cwindow = 0; + + cwindow->gui->lock_window("MWindow::show_cwindow"); + cwindow->gui->hide_window(); + cwindow->gui->unlock_window(); + gui->mainmenu->show_cwindow->set_checked(0); +} + + void MWindow::show_gwindow() { session->show_gwindow = 1; @@ -3005,6 +3198,7 @@ void MWindow::show_gwindow() gui->mainmenu->show_gwindow->set_checked(1); } + void MWindow::hide_gwindow() { session->show_gwindow = 0; @@ -3012,6 +3206,7 @@ void MWindow::hide_gwindow() gwindow->gui->lock_window("MWindow::show_gwindow"); gwindow->gui->hide_window(); gwindow->gui->unlock_window(); + gui->mainmenu->show_gwindow->set_checked(0); } void MWindow::show_lwindow() @@ -3025,6 +3220,17 @@ void MWindow::show_lwindow() gui->mainmenu->show_lwindow->set_checked(1); } +void MWindow::hide_lwindow() +{ + session->show_lwindow = 0; + + lwindow->gui->lock_window("MWindow::show_lwindow"); + lwindow->gui->hide_window(); + lwindow->gui->unlock_window(); + gui->mainmenu->show_lwindow->set_checked(0); +} + + void MWindow::restore_windows() { gui->unlock_window(); @@ -3054,7 +3260,7 @@ void MWindow::restore_windows() cwindow->gui->unlock_window(); } else if( session->show_cwindow && cwindow->gui->is_hidden() ) - cwindow->show_window(); + show_cwindow(); if( !session->show_gwindow && !gwindow->gui->is_hidden() ) { gwindow->gui->lock_window("MWindow::restore_windows"); @@ -4185,6 +4391,25 @@ void MWindow::get_backup_path(char *path, int len) cp += snprintf(cp, ep-cp, idx ? BACKUPn_FILE : BACKUP_FILE, idx); } +void MWindow::create_timestamped_copy_from_previous_backup(char *previouspath) +{ + if (previouspath == NULL) return; + char backup_path[BCTEXTLEN]; + backup_path[0] = 0; + time_t now = time(NULL); + struct tm* currenttime = localtime(&now); + snprintf(backup_path, sizeof(backup_path), + "%s/%s_%d%.2d%.2d_%.2d%.2d%.2d", + File::get_config_path(), BACKUP_FILE1, + currenttime->tm_year + 1900, + currenttime->tm_mon + 1, + currenttime->tm_mday, + currenttime->tm_hour, + currenttime->tm_min, + currenttime->tm_sec); + rename(previouspath, backup_path); +} + void MWindow::save_backup() { FileXML file; @@ -4195,6 +4420,8 @@ void MWindow::save_backup() snprintf(backup_path1, sizeof(backup_path1), "%s/%s", File::get_config_path(), BACKUP_FILE1); get_backup_path(backup_path, sizeof(backup_path)); + if( preferences->ongoing_backups ) + create_timestamped_copy_from_previous_backup(backup_path1); rename(backup_path, backup_path1); edl->save_xml(&file, backup_path); file.terminate_string(); @@ -4463,11 +4690,14 @@ static inline int gcd(int m, int n) int MWindow::create_aspect_ratio(float &w, float &h, int width, int height) { w = 1; h = 1; + double ar; + if(!width || !height) return 1; if( width == 720 && (height == 480 || height == 576) ) { w = 4; h = 3; return 0; // for NTSC and PAL } - double ar = (double)width / height; + + ar = (double)width / height; // square-ish pixels if( EQUIV(ar, 1.0000) ) return 0; if( EQUIV(ar, 1.3333) ) { w = 4; h = 3; return 0; } @@ -4475,6 +4705,8 @@ int MWindow::create_aspect_ratio(float &w, float &h, int width, int height) if( EQUIV(ar, 2.1111) ) { w = 19; h = 9; return 0; } if( EQUIV(ar, 2.2222) ) { w = 20; h = 9; return 0; } if( EQUIV(ar, 2.3333) ) { w = 21; h = 9; return 0; } + if( EQUIV(ar, 2.37037) ) { w = 64; h = 27; return 0; } + int ww = width, hh = height; // numerator, denominator must be under mx int mx = 255, n = gcd(ww, hh); @@ -5018,12 +5250,26 @@ int MWindow::select_asset(Asset *asset, int vstream, int astream, int delete_tra session->output_w = width; session->output_h = height; session->frame_rate = framerate; + session->interlace_mode = asset->interlace_mode; // not, asset->actual_width/actual_height asset->width = session->output_w; asset->height = session->output_h; asset->frame_rate = session->frame_rate; + create_aspect_ratio(session->aspect_w, session->aspect_h, session->output_w, session->output_h); + float ar = asset->aspect_ratio; + if (ar) { + //printf ("Aspect ratio from asset: %f \n", ar); + if( EQUIV(ar, 1.3333) ) { session->aspect_w = 4; session->aspect_h = 3; } + if( EQUIV(ar, 1.7777) ) { session->aspect_w = 16; session->aspect_h = 9; } + if( EQUIV(ar, 2.1111) ) { session->aspect_w = 19; session->aspect_h = 9; } + if( EQUIV(ar, 2.2222) ) { session->aspect_w = 20; session->aspect_h = 9; } + if( EQUIV(ar, 2.3333) ) { session->aspect_w = 21; session->aspect_h = 9; } + if( EQUIV(ar, 2.370370) ) { session->aspect_w = 64; session->aspect_h = 27; } + } + + Track *track = edl->tracks->first; for( Track *next_track=0; track; track=next_track ) { next_track = track->next; @@ -5058,7 +5304,7 @@ int MWindow::select_asset(Asset *asset, int vstream, int astream, int delete_tra int channels = 0; for( uint64_t mask=channel_mask; mask!=0; mask>>=1 ) channels += mask & 1; if( channels < 1 ) channels = 1; - if( channels > 6 ) channels = 6; + if( channels > MAXCHANNELS ) channels = MAXCHANNELS; session->audio_tracks = session->audio_channels = channels; int *achannel_positions = preferences->channel_positions[session->audio_channels-1]; @@ -5207,6 +5453,8 @@ ConfirmRefWindow::ConfirmRefWindow(MWindow *mwindow, char *path, { this->mwindow = mwindow; this->path = path; +// *** CONTEXT_HELP *** + context_help_set_keyword("File by Reference"); } ConfirmRefWindow::~ConfirmRefWindow()