no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / mwindow.C
index e63b7c54a8c629284fe682ad1822aa3831eddf0f..1291b99213fce9781c2fe883d733e9bb65cd6189 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * CINELERRA
  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
+ * 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
@@ -556,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<PluginServer*> plugins;
        while( !ret && !feof(fp) && fgets(index_line, BCTEXTLEN, fp) ) {
                if( index_line[0] == ';' ) continue;
@@ -579,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;
@@ -589,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);
@@ -605,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;
                }
        }
@@ -644,16 +675,27 @@ int MWindow::check_plugin_index(ArrayList<PluginServer*> &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<PluginServer*>;
        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: "
@@ -663,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: "
@@ -686,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+");
@@ -717,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: "
@@ -766,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;
                }
@@ -2160,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);
@@ -4325,7 +4393,7 @@ void MWindow::get_backup_path(char *path, int len)
 
 void MWindow::create_timestamped_copy_from_previous_backup(char *previouspath)
 {
-  if (previouspath == nullptr) return;
+  if (previouspath == NULL) return;
   char backup_path[BCTEXTLEN];
   backup_path[0] = 0;
   time_t now = time(NULL);
@@ -5236,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];
@@ -5385,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()