rerate: Add option to define a list with scene changes
authorAndreas Eversberg <jolly@eversberg.eu>
Fri, 9 Oct 2015 15:01:19 +0000 (17:01 +0200)
committerAndreas Eversberg <jolly@eversberg.eu>
Sat, 14 May 2016 10:55:53 +0000 (12:55 +0200)
Whenever a scene changes, no intermediate frame is rendered.
Instead, the rendering stats on the new scene.

tools/rerate.c

index f2d5cbf..0a8ebd2 100644 (file)
@@ -4,6 +4,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <math.h>
+#include <errno.h>
 #include "../src/img.h"
 #include <opencv2/core/core_c.h>
 #include <opencv2/imgproc/imgproc_c.h>
 /* test input image */
 //#define TEST_INPUT
 
+struct scenes {
+       struct scenes *next;
+       int frame;
+} *scenes_start = NULL;
+
 int flow_window = 30, border = 0;
 double limit_frames = 0;
 int interlace = 0, swap = 0;
+char scenes_file[256] = "";
+
+static int load_scenes(const char *filename)
+{
+       FILE *fp;
+       struct scenes *scenes, **scenesp = &scenes_start;
+       char buffer[256];
+       int frame = 0;
+       int line = 0;
+
+       fp = fopen(filename, "r");
+       if (!fp) {
+               fprintf(stderr, "Failed to open scenes file '%s'\n", filename);
+               return -EIO;
+       }
+
+       while ((fgets(buffer, sizeof(buffer), fp))) {
+               line++;
+               buffer[sizeof(buffer)-1] = '\0';
+               if (buffer[0]) buffer[strlen(buffer)-1] = '\0';
+               if (buffer[0] == '\0')
+                       continue;
+               if (buffer[0] < '0' || buffer[0] > '9') {
+                       fprintf(stderr, "Error in scenes file. Expecting frame number in line %d.\n", line);
+                       return -EINVAL;
+               }
+               if (atoi(buffer) == 0 && frame == 0)
+                       continue;
+               if (atoi(buffer) <= frame) {
+                       fprintf(stderr, "Error in scenes file. Expecting ascending frame number in line %d.\n", line);
+                       return -EINVAL;
+               }
+               scenes = calloc(sizeof(*scenes), 1);
+               if (!scenes)
+                       return -ENOMEM;
+               scenes->frame = atoi(buffer);
+               frame = scenes->frame;
+               *scenesp = scenes;
+               scenesp = &scenes->next;
+       }
+
+       if (!scenes_start) {
+               fprintf(stderr, "Error in scenes file. No frame numbers found.\n");
+               return -EINVAL;
+       }
+
+       scenes = scenes_start;
+       frame = 0;
+       while(scenes) {
+               printf("Scene: %d - %d\n", frame, scenes->frame);
+               frame = scenes->frame;
+               scenes = scenes->next;
+       }
+       printf("Scene: %d - end\n", frame);
+
+       fclose(fp);
+       return 0;
+}
 
 static void field_img(int width, int height, unsigned short *img, int odd)
 {
@@ -320,6 +384,10 @@ static void print_help(const char *app)
        printf(" -b --border <pixles> Remove border pixles, if darker than image (try 1)\n");
        printf(" -w --window <size>   Change optical flow window size (default %d)\n", flow_window);
        printf(" -f --frames <number> Limit number of input frames (default infinite)\n");
+       printf(" -S --scenes <file>   Use given file to seperate scene changes, to avoid interpolation.\n");
+       printf("                      Note: Output images that would be between two scenes get dropped.\n");
+       printf("                      Frames between scene changes are dropped.\n");
+       printf("                      The list must contain one frame number per line in ascending order.\n");
        printf(" -i --interlace       Handle input image as interlaced image\n");
        printf("                      Note: oldfps refers to frames, not the individual fields\n");
        printf(" -e --even            Use even lines for first field, instead of odd lines\n");
@@ -342,12 +410,13 @@ static int handle_options(int argc, char **argv)
                        {"border", 1, 0, 'b'},
                        {"window", 1, 0, 'w'},
                        {"frames", 1, 0, 'f'},
+                       {"scenes", 1, 0, 'S'},
                        {"interlace", 0, 0, 'i'},
                        {"even", 0, 0, 'e'},
                        {0, 0, 0, 0},
                };
 
-               c = getopt_long(argc, argv, "hd:b:w:f:ie", long_options, &option_index);
+               c = getopt_long(argc, argv, "hd:b:w:f:S:ie", long_options, &option_index);
 
                if (c == -1)
                        break;
@@ -372,6 +441,10 @@ static int handle_options(int argc, char **argv)
                        limit_frames = atoi(optarg);
                        skip_args += 2;
                        break;
+               case 'S':
+                       strcpy(scenes_file, optarg);
+                       skip_args += 2;
+                       break;
                case 'i':
                        interlace = 1;
                        skip_args++;
@@ -381,6 +454,7 @@ static int handle_options(int argc, char **argv)
                        skip_args++;
                        break;
                default:
+                       fprintf(stderr, "internal parse error\n");
                        break;
                }
        }
@@ -404,6 +478,8 @@ int main(int argc, char *argv[])
        argv += skip_args + 1;
 
        if (argc != 6) {
+               if (argc > 1)
+                       fprintf(stderr, "Please give correct number of arguments!\n\n");
                print_help(app_name);
                return 0;
        }
@@ -420,8 +496,14 @@ int main(int argc, char *argv[])
        printf("Optical Flow window: %d\n", flow_window);
        if (limit_frames)
                printf("Limit number of input frames: %.0f\n", limit_frames);
+       if (scenes_file[0]) {
+               rc = load_scenes(scenes_file);
+               if (rc)
+                       goto out;
+       }
 
 next_frame:
+       /* calc and round baseframe and offet */
        baseframe = floor(inputframe);
        offset = inputframe - baseframe;
        if (offset < 0.001)
@@ -432,6 +514,26 @@ next_frame:
                offset = 0.0;
                baseframe++;
        }
+       /* detect scene change */
+       if (scenes_start) {
+               /* check if we passed a scene change */
+               while (scenes_start && scenes_start->frame <= baseframe) {
+                       printf("Enter new scene at frame %d\n", scenes_start->frame);
+                       scenes_start = scenes_start->next;
+               }
+       }
+       if (scenes_start) {
+               /* check if we would interpolate between scenes, so we skip that */
+               if (scenes_start->frame == baseframe+1 /* next frame has a new scene */
+                && offset >= 0.0 /* not just copy base frame */
+                && !(interlace && offset <= 0.5)) { /* not interpolate interlaced fields */
+                       printf("Skipping frame %.4f due to scene change at frame %d\n", inputframe, scenes_start->frame);
+                       inputframe = baseframe+1;
+                       scenes_start = scenes_start->next;
+                       goto next_frame;
+               }
+       }
+       /* copy frames that match exactly */
        if (offset == 0.0 || (interlace && offset == 0.5)) {
                if (interlace) {
                        if (offset < 0.5)
@@ -453,6 +555,7 @@ next_frame:
                if (rc < 0)
                        goto out;
        } else {
+       /* interpolate frames that are in between */
                printf("Processing input frame %.4f, output frame %d\n", inputframe, outputframe);
                img1 = load_img(&width, &height, inputname, baseframe);
                if (!img1)