Fix T53003: IMB: Invalid framerate handling due to short integer overflow.
authorBastien Montagne <montagne29@wanadoo.fr>
Fri, 26 Jan 2018 13:59:16 +0000 (14:59 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Fri, 26 Jan 2018 13:59:16 +0000 (14:59 +0100)
FFMPEG uses int for the numerator, while Blender uses a short. So in
cases people gave weird exotic framerate values and we cannot reduce
enough the numerator, we'd get totally weird values (even negative frame
rates sometimes!)

Now we add checks for short overflow and approximate as best as possible
in that case (error should not matter unless you have shots of at least
several hundreds of hours ;) ).

source/blender/imbuf/intern/IMB_anim.h
source/blender/imbuf/intern/anim_movie.c

index b10ae4f6fe90aef604341694e70ba1c6836cd717..c4c4f4405a50e43ffd210461af8f9530b6415472 100644 (file)
@@ -99,8 +99,8 @@ struct anim {
        int curtype;
        int curposition;    /* index  0 = 1e,  1 = 2e, enz. */
        int duration;
-       short frs_sec;
-       float frs_sec_base;
+       int frs_sec;
+       double frs_sec_base;
        int x, y;
        
        /* for number */
index 25b0c0d7b1ac9c60b51d8e9a31bf3c393aa53768..4f535a26c3b1c1682cc933cc8b9053ea77269ae5 100644 (file)
@@ -55,6 +55,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
+#include <limits.h>
 #ifndef _WIN32
 #include <dirent.h>
 #else
@@ -1365,15 +1366,28 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
 bool IMB_anim_get_fps(struct anim *anim,
                      short *frs_sec, float *frs_sec_base, bool no_av_base)
 {
+       double frs_sec_base_double;
        if (anim->frs_sec) {
-               *frs_sec = anim->frs_sec;
-               *frs_sec_base = anim->frs_sec_base;
+               if (anim->frs_sec > SHRT_MAX) {
+                       /* We cannot store original rational in our short/float format,
+                        * we need to approximate it as best as we can... */
+                       *frs_sec = SHRT_MAX;
+                       frs_sec_base_double = anim->frs_sec_base * (double)SHRT_MAX / (double)anim->frs_sec;
+               }
+               else {
+                       *frs_sec = anim->frs_sec;
+                       frs_sec_base_double = anim->frs_sec_base;
+               }
 #ifdef WITH_FFMPEG
                if (no_av_base) {
-                       *frs_sec_base /= AV_TIME_BASE;
+                       *frs_sec_base = (float)(frs_sec_base_double / AV_TIME_BASE);
+               }
+               else {
+                       *frs_sec_base = (float)frs_sec_base_double;
                }
 #else
                UNUSED_VARS(no_av_base);
+               *frs_sec_base = (float)frs_sec_base_double;
 #endif
                return true;
        }