load image sequence faster by parsing directory
authorAndreas Eversberg <jolly@eversberg.eu>
Sat, 10 Oct 2015 07:38:24 +0000 (09:38 +0200)
committerAndreas Eversberg <jolly@eversberg.eu>
Sat, 14 May 2016 10:55:53 +0000 (12:55 +0200)
gui/timeline.c

index c6590f0..ba06625 100644 (file)
 #include "../src/opticalflow.h"
 #endif
 
+/* functions to load directory */
+
+typedef struct dir_entry {
+       struct dir_entry        *next;
+       char name[0];
+} dir_t;
+
+static int cmpstringp(const void *p1, const void *p2)
+{
+       dir_t *entry1 = *(dir_t **)p1;
+       dir_t *entry2 = *(dir_t **)p2;
+
+       return strcmp(entry1->name, entry2->name);
+}
+
+static dir_t *fetch_dir(const char *path) /* NOTE: if path is not empty, it must end with DIR_SEPERATOR */
+{
+       int rc;
+       DIR *dir;
+       struct dirent dirent, *result;
+       dir_t *head = NULL, *entry, **entryp = &head;
+       int count = 0;
+       dir_t **list;
+       int i;
+
+       /* read linked list */
+       dir = opendir(path);
+       if (!dir)
+               return NULL;
+       while (1) {
+               rc = readdir_r(dir, &dirent, &result);
+               if (rc < 0)
+                       break;
+               if (result == NULL)
+                       break;
+               if (result->d_type != DT_REG && result->d_type != DT_LNK)
+                       continue;
+               entry = calloc(1, sizeof(dir_t) + strlen(path) + strlen(result->d_name) + 1);
+               if (!entry) {
+                       fprintf(stderr, "no memory");
+                       return NULL;
+               }
+               *entryp = entry;
+               entryp = &entry->next;
+               strcpy(entry->name, path);
+               strcat(entry->name, result->d_name);
+               count++;
+       }
+       closedir(dir);
+
+       /* sort linked list */
+       list = calloc(count, sizeof(*list));
+       if (!list) {
+               fprintf(stderr, "no memory");
+               return NULL;
+       }
+       count = 0;
+       for (entry = head; entry; entry = entry->next) {
+               list[count] = entry;
+               count++;
+       }
+       qsort(list, count, sizeof(*list), cmpstringp);
+       entryp = &head;
+       for (i = 0; i < count; i++) {
+               /* relink */
+               entry = list[i];
+               entry->next = NULL;
+               *entryp = entry;
+               entryp = &entry->next;
+       }
+       free(list);
+
+       return head;
+}
+
+static void free_dir(dir_t *dir)
+{
+       dir_t *entry, *next;
+
+       entry = dir;
+       while (entry) {
+               next = entry->next;
+               free(entry);
+               entry = next;
+       }
+}
+
+
 struct frame_list *frame_list = NULL;
 
 /* currently loaded image */
@@ -83,12 +171,29 @@ static void draw_timeline_frame(int frame)
        }
 }
 
+/* get path of given file name */
+static char *get_path(const char *filename)
+{
+       static char path[256];
+
+       /* copy name */
+       strcpy(path, filename);
+       /* remove until DIR_SEPERATOR */
+       while (path[0]) {
+               if (path[strlen(path) - 1] == DIR_SEPERATOR)
+                       break;
+               path[strlen(path) - 1] = '\0';
+       }
+
+       return path;
+}
+
 /* load directory and create pixbuf */
 void create_timeline(const char *filename)
 {
        int i;
        const char *p, *q;
-       char temp[256], name[256], suffix[256];
+       char temp[256], suffix[256];
        FILE *fp;
 
        if (filename) {
@@ -131,44 +236,61 @@ single_file:
                        strcpy(frame_list[0].filename, filename);
                        timeline_frames = 1;
                } else {
-                       /* calculate image file name */
+                       /* create list of files that have same base name, same number of digits and suffix */
+                       int suffix_offset = strlen(filename) - strlen(suffix);
+                       int digits_offset = p - filename;
                        int digits = filename + strlen(filename) - strlen(suffix) - p;
-                       int start, count = 0;
-                       strncpy(temp, p, digits);
-                       temp[digits] = '\0';
-                       start = atoi(temp);
-//                     printf("count digits=%s num=%d start=%d\n", temp, digits, start);
-                       strncpy(temp, filename, p - filename);
-                       temp[p - filename] = '\0';
-//                     printf("prefix=%s\n", temp);
-                       sprintf(strchr(temp, '\0'), "%%0%dd%s", digits, suffix);
-//                     printf("complete=%s\n", temp);
-                       /* look back for index */
-                       while (start > 0) {
-                               sprintf(name, temp, start - 1);
-                               fp = fopen(name, "r");
-                               if (!fp)
-                                       break;
-                               fclose(fp);
-                               start--;
+                       const char *path = get_path(filename);
+                       dir_t *dir_head = fetch_dir(path), *dir, **dirp;
+                       int count;
+                       if (!dir_head)
+                               goto single_file;
+                       dir = dir_head;
+                       dirp = &dir_head;
+                       while (dir) {
+                               /* remove files that do not have equal prefix */
+                               if (!!strncmp(filename, dir->name, p - filename)) {
+free_file:
+                                       /* remove entry */
+                                       *dirp = dir->next;
+                                       free(dir);
+                                       dir = *dirp;
+                                       continue;
+                               }
+                               /* remove files that have no digits where expected */
+                               for (i = 0; i < digits; i++) {
+                                       if (dir->name[digits_offset+i] < '0' || dir->name[digits_offset+i] > '9')
+                                               break;
+                               }
+                               if (i < digits) {
+                                       goto free_file;
+                               }
+                               /* remove files that have different suffix */
+                               if (!!strcmp(suffix, dir->name + suffix_offset)) {
+                                       goto free_file;
+                               }
+                               dirp = &(dir->next);
+                               dir = dir->next;
                        }
-                       /* count forward index */
-                       for (i = start; ; i++) {
-                               sprintf(name, temp, start + count);
-                               fp = fopen(name, "r");
-                               if (!fp)
-                                       break;
-                               fclose(fp);
+                       count = 0;
+                       dir = dir_head;
+                       while (dir) {
                                count++;
+                               dir = dir->next;
                        }
-                       if (count == 0)
+                       if (count < 2) {
+                               free_dir(dir_head);
                                goto single_file;
+                       }
                        frame_list = malloc(sizeof(struct frame_list) * count);
                        memset(frame_list, 0, sizeof(struct frame_list) * count);
+                       dir = dir_head;
                        for (i = 0; i < count; i++) {
-                               sprintf(frame_list[i].filename, temp, start + i);
+                               strcpy(frame_list[i].filename, dir->name);
+                               dir = dir->next;
                        }
                        timeline_frames = count;
+                       free_dir(dir_head);
                }
                /* get marked frames */
                for (i = 0; i < timeline_frames; i++) {
@@ -382,18 +504,12 @@ int timeline_clicked(int x, int y)
 }
 
 /* get filename of first grey image directory */
-static char *get_filename(const char *filename)
+static char *get_sequence_name(const char *filename)
 {
        static char name[256];
 
        /* copy name */
-       strcpy(name, filename);
-       /* remove until DIR_SEPERATOR */
-       while (name[0]) {
-               if (name[strlen(name) - 1] == DIR_SEPERATOR)
-                       break;
-               name[strlen(name) - 1] = '\0';
-       }
+       strcpy(name, get_path(filename));
        /* add palette name */
        strcat(name, "sequence");
 
@@ -412,7 +528,7 @@ int save_sequence(void)
        if (timeline_frames <= 1)
                return 0;
 
-       name = get_filename(frame_list[0].filename);
+       name = get_sequence_name(frame_list[0].filename);
 //     printf("save sequence '%s'\n", name);
        fp = fopen(name, "w");
        if (!fp) {
@@ -444,11 +560,11 @@ int load_sequence(void)
        if (timeline_frames <= 1)
                return 0;
 
-       name = get_filename(frame_list[0].filename);
+       name = get_sequence_name(frame_list[0].filename);
 //     printf("load sequence '%s'\n", name);
        fp = fopen(name, "r");
        if (!fp) {
-               printf("failed to load sequence '%s'\n", name);
+               printf("no sequence file '%s' created yet\n", name);
                return -1;
        }
        for (i = 0; i < timeline_frames; i++) {