Code cleanup: use r_ prefix for return args
[blender.git] / source / blender / blenkernel / intern / image.c
index 7f0475cf15548f809e6b1ee7fd3c689abbd8ef76..aaeead431b947560bb6b8f80a7c0a23f666bd579 100644 (file)
 #include <fcntl.h>
 #include <math.h>
 #ifndef WIN32
-#include <unistd.h>
+#  include <unistd.h>
 #else
-#include <io.h>
+#  include <io.h>
 #endif
 
 #include <time.h>
 
 #ifdef _WIN32
-#define open _open
-#define close _close
+#  define open _open
+#  define close _close
 #endif
 
 #include "MEM_guardedalloc.h"
 #include "IMB_colormanagement.h"
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
+#include "IMB_moviecache.h"
 
 #ifdef WITH_OPENEXR
-#include "intern/openexr/openexr_multi.h"
+#  include "intern/openexr/openexr_multi.h"
 #endif
 
 #include "DNA_packedFile_types.h"
@@ -67,6 +68,7 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_threads.h"
+#include "BLI_timecode.h"  /* for stamp timecode format */
 #include "BLI_utildefines.h"
 
 #include "BKE_bmfont.h"
@@ -89,7 +91,7 @@
 
 #include "GPU_draw.h"
 
-#include "BLO_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
 
 /* for image user iteration */
 #include "DNA_node_types.h"
@@ -107,7 +109,57 @@ static SpinLock image_spin;
 /* quick lookup: supports 1 million frames, thousand passes */
 #define IMA_MAKE_INDEX(frame, index)    ((frame) << 10) + index
 #define IMA_INDEX_FRAME(index)          (index >> 10)
+/*
 #define IMA_INDEX_PASS(index)           (index & ~1023)
+*/
+
+/* ******** IMAGE CACHE ************* */
+
+typedef struct ImageCacheKey {
+       int index;
+} ImageCacheKey;
+
+static unsigned int imagecache_hashhash(const void *key_v)
+{
+       const ImageCacheKey *key = (ImageCacheKey *) key_v;
+       return key->index;
+}
+
+static int imagecache_hashcmp(const void *a_v, const void *b_v)
+{
+       const ImageCacheKey *a = (ImageCacheKey *) a_v;
+       const ImageCacheKey *b = (ImageCacheKey *) b_v;
+
+       return a->index - b->index;
+}
+
+static void imagecache_put(Image *image, int index, ImBuf *ibuf)
+{
+       ImageCacheKey key;
+
+       if (image->cache == NULL) {
+               // char cache_name[64];
+               // BLI_snprintf(cache_name, sizeof(cache_name), "Image Datablock %s", image->id.name);
+
+               image->cache = IMB_moviecache_create("Image Datablock Cache", sizeof(ImageCacheKey),
+                                                    imagecache_hashhash, imagecache_hashcmp);
+       }
+
+       key.index = index;
+
+       IMB_moviecache_put(image->cache, &key, ibuf);
+}
+
+static struct ImBuf *imagecache_get(Image *image, int index)
+{
+       if (image->cache) {
+               ImageCacheKey key;
+               key.index = index;
+               return IMB_moviecache_get(image->cache, &key);
+       }
+
+       return NULL;
+}
 
 void BKE_images_init(void)
 {
@@ -191,19 +243,17 @@ void BKE_image_de_interlace(Image *ima, int odd)
 
 /* ***************** ALLOC & FREE, DATA MANAGING *************** */
 
-static void image_free_buffers(Image *ima)
+static void image_free_cahced_frames(Image *image)
 {
-       ImBuf *ibuf;
-
-       while ((ibuf = ima->ibufs.first)) {
-               BLI_remlink(&ima->ibufs, ibuf);
-
-               if (ibuf->userdata) {
-                       MEM_freeN(ibuf->userdata);
-                       ibuf->userdata = NULL;
-               }
-               IMB_freeImBuf(ibuf);
+       if (image->cache) {
+               IMB_moviecache_free(image->cache);
+               image->cache = NULL;
        }
+}
+
+static void image_free_buffers(Image *ima)
+{
+       image_free_cahced_frames(ima);
 
        if (ima->anim) IMB_free_anim(ima->anim);
        ima->anim = NULL;
@@ -242,11 +292,11 @@ void BKE_image_free(Image *ima)
 }
 
 /* only image block itself */
-static Image *image_alloc(const char *name, short source, short type)
+static Image *image_alloc(Main *bmain, const char *name, short source, short type)
 {
        Image *ima;
 
-       ima = BKE_libblock_alloc(&G.main->image, ID_IM, name);
+       ima = BKE_libblock_alloc(bmain, ID_IM, name);
        if (ima) {
                ima->ok = IMA_OK;
 
@@ -266,70 +316,37 @@ static Image *image_alloc(const char *name, short source, short type)
        return ima;
 }
 
-/* get the ibuf from an image cache, local use here only */
-static ImBuf *image_get_ibuf(Image *ima, int index, int frame)
+/* Get the ibuf from an image cache by it's index and frame.
+ * Local use here only.
+ *
+ * Returns referenced image buffer if it exists, callee is to
+ * call IMB_freeImBuf to de-reference the image buffer after
+ * it's done handling it.
+ */
+static ImBuf *image_get_cached_ibuf_for_index_frame(Image *ima, int index, int frame)
 {
-       /* this function is intended to be thread safe. with IMA_NO_INDEX this
-        * should be OK, but when iterating over the list this is more tricky
-        * */
-       if (index == IMA_NO_INDEX) {
-               return ima->ibufs.first;
-       }
-       else {
-               ImBuf *ibuf;
-
+       if (index != IMA_NO_INDEX) {
                index = IMA_MAKE_INDEX(frame, index);
-               for (ibuf = ima->ibufs.first; ibuf; ibuf = ibuf->next)
-                       if (ibuf->index == index)
-                               return ibuf;
        }
 
-       return NULL;
-}
-
-/* no ima->ibuf anymore, but listbase */
-static void image_remove_ibuf(Image *ima, ImBuf *ibuf)
-{
-       if (ibuf) {
-               BLI_remlink(&ima->ibufs, ibuf);
-               IMB_freeImBuf(ibuf);
-       }
+       return imagecache_get(ima, index);
 }
 
-
 /* no ima->ibuf anymore, but listbase */
 static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
 {
        if (ibuf) {
-               ImBuf *link;
-
                if (index != IMA_NO_INDEX)
                        index = IMA_MAKE_INDEX(frame, index);
 
-               /* insert based on index */
-               for (link = ima->ibufs.first; link; link = link->next)
-                       if (link->index >= index)
-                               break;
-
-               ibuf->index = index;
-               if (ima->flag & IMA_CM_PREDIVIDE)
-                       ibuf->flags |= IB_cm_predivide;
-               else
-                       ibuf->flags &= ~IB_cm_predivide;
-
-               /* this function accepts (link == NULL) */
-               BLI_insertlinkbefore(&ima->ibufs, link, ibuf);
-
-               /* now we don't want copies? */
-               if (link && ibuf->index == link->index)
-                       image_remove_ibuf(ima, link);
+               imagecache_put(ima, index, ibuf);
        }
 }
 
 /* empty image block, of similar type and filename */
-Image *BKE_image_copy(Image *ima)
+Image *BKE_image_copy(Main *bmain, Image *ima)
 {
-       Image *nima = image_alloc(ima->id.name + 2, ima->source, ima->type);
+       Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
 
        BLI_strncpy(nima->name, ima->name, sizeof(ima->name));
 
@@ -347,6 +364,9 @@ Image *BKE_image_copy(Image *ima)
 
        BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings);
 
+       if (ima->packedfile)
+               nima->packedfile = dupPackedFile(ima->packedfile);
+
        return nima;
 }
 
@@ -437,7 +457,7 @@ void BKE_image_make_local(struct Image *ima)
                extern_local_image(ima);
        }
        else if (is_local && is_lib) {
-               Image *ima_new = BKE_image_copy(ima);
+               Image *ima_new = BKE_image_copy(bmain, ima);
 
                ima_new->id.us = 0;
 
@@ -520,22 +540,28 @@ void BKE_image_make_local(struct Image *ima)
 
 void BKE_image_merge(Image *dest, Image *source)
 {
-       ImBuf *ibuf;
-
        /* sanity check */
        if (dest && source && dest != source) {
-
-               while ((ibuf = source->ibufs.first)) {
-                       BLI_remlink(&source->ibufs, ibuf);
-                       image_assign_ibuf(dest, ibuf, IMA_INDEX_PASS(ibuf->index), IMA_INDEX_FRAME(ibuf->index));
+               BLI_spin_lock(&image_spin);
+               if (source->cache != NULL) {
+                       struct MovieCacheIter *iter;
+                       iter = IMB_moviecacheIter_new(source->cache);
+                       while (!IMB_moviecacheIter_done(iter)) {
+                               ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+                               ImageCacheKey *key = IMB_moviecacheIter_getUserKey(iter);
+                               imagecache_put(dest, key->index, ibuf);
+                               IMB_moviecacheIter_step(iter);
+                       }
+                       IMB_moviecacheIter_free(iter);
                }
+               BLI_spin_unlock(&image_spin);
 
-               BKE_libblock_free(&G.main->image, source);
+               BKE_libblock_free(G.main, source);
        }
 }
 
 /* note, we could be clever and scale all imbuf's but since some are mipmaps its not so simple */
-int BKE_image_scale(Image *image, int width, int height)
+bool BKE_image_scale(Image *image, int width, int height)
 {
        ImBuf *ibuf;
        void *lock;
@@ -552,7 +578,42 @@ int BKE_image_scale(Image *image, int width, int height)
        return (ibuf != NULL);
 }
 
-Image *BKE_image_load(const char *filepath)
+static void image_init_color_management(Image *ima)
+{
+       ImBuf *ibuf;
+       char name[FILE_MAX];
+
+       BKE_image_user_file_path(NULL, ima, name);
+
+       /* will set input color space to image format default's */
+       ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, ima->colorspace_settings.name);
+
+       if (ibuf) {
+               if (ibuf->flags & IB_alphamode_premul)
+                       ima->alpha_mode = IMA_ALPHA_PREMUL;
+               else
+                       ima->alpha_mode = IMA_ALPHA_STRAIGHT;
+
+               IMB_freeImBuf(ibuf);
+       }
+}
+
+char BKE_image_alpha_mode_from_extension_ex(const char *filepath)
+{
+       if (BLI_testextensie_n(filepath, ".exr", ".cin", ".dpx", ".hdr", NULL)) {
+               return IMA_ALPHA_PREMUL;
+       }
+       else {
+               return IMA_ALPHA_STRAIGHT;
+       }
+}
+
+void BKE_image_alpha_mode_from_extension(Image *image)
+{
+       image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->name);
+}
+
+Image *BKE_image_load(Main *bmain, const char *filepath)
 {
        Image *ima;
        int file, len;
@@ -560,11 +621,12 @@ Image *BKE_image_load(const char *filepath)
        char str[FILE_MAX];
 
        BLI_strncpy(str, filepath, sizeof(str));
-       BLI_path_abs(str, G.main->name);
+       BLI_path_abs(str, bmain->name);
 
        /* exists? */
        file = BLI_open(str, O_BINARY | O_RDONLY, 0);
-       if (file == -1) return NULL;
+       if (file < 0)
+               return NULL;
        close(file);
 
        /* create a short library name */
@@ -573,12 +635,14 @@ Image *BKE_image_load(const char *filepath)
        while (len > 0 && filepath[len - 1] != '/' && filepath[len - 1] != '\\') len--;
        libname = filepath + len;
 
-       ima = image_alloc(libname, IMA_SRC_FILE, IMA_TYPE_IMAGE);
+       ima = image_alloc(bmain, libname, IMA_SRC_FILE, IMA_TYPE_IMAGE);
        BLI_strncpy(ima->name, filepath, sizeof(ima->name));
 
        if (BLI_testextensie_array(filepath, imb_ext_movie))
                ima->source = IMA_SRC_MOVIE;
 
+       image_init_color_management(ima);
+
        return ima;
 }
 
@@ -598,7 +662,7 @@ Image *BKE_image_load_exists(const char *filepath)
        for (ima = G.main->image.first; ima; ima = ima->id.next) {
                if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) {
                        BLI_strncpy(strtest, ima->name, sizeof(ima->name));
-                       BLI_path_abs(strtest, G.main->name);
+                       BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id));
 
                        if (BLI_path_cmp(strtest, str) == 0) {
                                if (ima->anim == NULL || ima->id.us == 0) {
@@ -613,11 +677,11 @@ Image *BKE_image_load_exists(const char *filepath)
                }
        }
 
-       return BKE_image_load(filepath);
+       return BKE_image_load(G.main, filepath);
 }
 
 static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type,
-                            float color[4], ColorManagedColorspaceSettings *colorspace_settings)
+                            const float color[4], ColorManagedColorspaceSettings *colorspace_settings)
 {
        ImBuf *ibuf;
        unsigned char *rect = NULL;
@@ -625,7 +689,6 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
 
        if (floatbuf) {
                ibuf = IMB_allocImBuf(width, height, depth, IB_rectfloat);
-               rect_float = ibuf->rect_float;
 
                if (colorspace_settings->name[0] == '\0') {
                        const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT);
@@ -633,11 +696,13 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
                        BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name));
                }
 
-               IMB_colormanagement_check_is_data(ibuf, colorspace_settings->name);
+               if (ibuf != NULL) {
+                       rect_float = ibuf->rect_float;
+                       IMB_colormanagement_check_is_data(ibuf, colorspace_settings->name);
+               }
        }
        else {
                ibuf = IMB_allocImBuf(width, height, depth, IB_rect);
-               rect = (unsigned char *)ibuf->rect;
 
                if (colorspace_settings->name[0] == '\0') {
                        const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
@@ -645,7 +710,14 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
                        BLI_strncpy(colorspace_settings->name, colorspace, sizeof(colorspace_settings->name));
                }
 
-               IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace_settings->name);
+               if (ibuf != NULL) {
+                       rect = (unsigned char *)ibuf->rect;
+                       IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace_settings->name);
+               }
+       }
+
+       if (!ibuf) {
+               return NULL;
        }
 
        BLI_strncpy(ibuf->name, name, sizeof(ibuf->name));
@@ -660,23 +732,24 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
                        break;
                default:
                        BKE_image_buf_fill_color(rect, rect_float, width, height, color);
+                       break;
        }
 
        if (rect_float) {
                /* both byte and float buffers are filling in sRGB space, need to linearize float buffer after BKE_image_buf_fill* functions */
 
                IMB_buffer_float_from_float(rect_float, rect_float, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB,
-                                           ibuf->flags & IB_cm_predivide, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+                                           TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
        }
 
        return ibuf;
 }
 
 /* adds new image block, creates ImBuf and initializes color */
-Image *BKE_image_add_generated(unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, float color[4])
+Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4])
 {
        /* on save, type is changed to FILE in editsima.c */
-       Image *ima = image_alloc(name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+       Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
 
        if (ima) {
                ImBuf *ibuf;
@@ -686,10 +759,14 @@ Image *BKE_image_add_generated(unsigned int width, unsigned int height, const ch
                ima->gen_y = height;
                ima->gen_type = gen_type;
                ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0);
+               ima->gen_depth = depth;
 
                ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
                image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
 
+               /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
+               IMB_freeImBuf(ibuf);
+
                ima->ok = IMA_OK_LOADED;
        }
 
@@ -702,7 +779,7 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
        /* on save, type is changed to FILE in editsima.c */
        Image *ima;
 
-       ima = image_alloc(BLI_path_basename(ibuf->name), IMA_SRC_FILE, IMA_TYPE_IMAGE);
+       ima = image_alloc(G.main, BLI_path_basename(ibuf->name), IMA_SRC_FILE, IMA_TYPE_IMAGE);
 
        if (ima) {
                BLI_strncpy(ima->name, ibuf->name, FILE_MAX);
@@ -716,7 +793,7 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
 /* packs rect from memory as PNG */
 void BKE_image_memorypack(Image *ima)
 {
-       ImBuf *ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0);
+       ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
 
        if (ibuf == NULL)
                return;
@@ -747,6 +824,8 @@ void BKE_image_memorypack(Image *ima)
                        ima->type = IMA_TYPE_IMAGE;
                }
        }
+
+       IMB_freeImBuf(ibuf);
 }
 
 void BKE_image_tag_time(Image *ima)
@@ -799,7 +878,7 @@ void free_old_images(void)
                                ima->lastused = ctime;
                        }
                        /* Otherwise, just kill the buffers */
-                       else if (ima->ibufs.first) {
+                       else {
                                image_free_buffers(ima);
                        }
                }
@@ -807,30 +886,47 @@ void free_old_images(void)
        }
 }
 
-static uintptr_t image_mem_size(Image *ima)
+static uintptr_t image_mem_size(Image *image)
 {
-       ImBuf *ibuf, *ibufm;
-       int level;
        uintptr_t size = 0;
 
-       size = 0;
-
        /* viewers have memory depending on other rules, has no valid rect pointer */
-       if (ima->source == IMA_SRC_VIEWER)
+       if (image->source == IMA_SRC_VIEWER)
                return 0;
 
-       for (ibuf = ima->ibufs.first; ibuf; ibuf = ibuf->next) {
-               if (ibuf->rect) size += MEM_allocN_len(ibuf->rect);
-               else if (ibuf->rect_float) size += MEM_allocN_len(ibuf->rect_float);
+       BLI_spin_lock(&image_spin);
+       if (image->cache != NULL) {
+               struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+
+               while (!IMB_moviecacheIter_done(iter)) {
+                       ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+                       ImBuf *ibufm;
+                       int level;
 
-               for (level = 0; level < IB_MIPMAP_LEVELS; level++) {
-                       ibufm = ibuf->mipmap[level];
-                       if (ibufm) {
-                               if (ibufm->rect) size += MEM_allocN_len(ibufm->rect);
-                               else if (ibufm->rect_float) size += MEM_allocN_len(ibufm->rect_float);
+                       if (ibuf->rect) {
+                               size += MEM_allocN_len(ibuf->rect);
                        }
+                       if (ibuf->rect_float) {
+                               size += MEM_allocN_len(ibuf->rect_float);
+                       }
+
+                       for (level = 0; level < IB_MIPMAP_LEVELS; level++) {
+                               ibufm = ibuf->mipmap[level];
+                               if (ibufm) {
+                                       if (ibufm->rect) {
+                                               size += MEM_allocN_len(ibufm->rect);
+                                       }
+                                       if (ibufm->rect_float) {
+                                               size += MEM_allocN_len(ibufm->rect_float);
+                                       }
+                               }
+                       }
+
+                       IMB_moviecacheIter_step(iter);
                }
+               IMB_moviecacheIter_free(iter);
        }
+       BLI_spin_unlock(&image_spin);
 
        return size;
 }
@@ -853,11 +949,20 @@ void BKE_image_print_memlist(void)
        }
 }
 
+static bool imagecache_check_dirty(ImBuf *ibuf, void *UNUSED(userkey), void *UNUSED(userdata))
+{
+       return (ibuf->userflags & IB_BITMAPDIRTY) == 0;
+}
+
 void BKE_image_free_all_textures(void)
 {
+#undef CHECK_FREED_SIZE
+
        Tex *tex;
        Image *ima;
-       /* unsigned int totsize = 0; */
+#ifdef CHECK_FREED_SIZE
+       uintptr_t tot_freed_size = 0;
+#endif
 
        for (ima = G.main->image.first; ima; ima = ima->id.next)
                ima->id.flag &= ~LIB_DOIT;
@@ -867,49 +972,39 @@ void BKE_image_free_all_textures(void)
                        tex->ima->id.flag |= LIB_DOIT;
 
        for (ima = G.main->image.first; ima; ima = ima->id.next) {
-               if (ima->ibufs.first && (ima->id.flag & LIB_DOIT)) {
-                       ImBuf *ibuf;
+               if (ima->cache && (ima->id.flag & LIB_DOIT)) {
+#ifdef CHECK_FREED_SIZE
+                       uintptr_t old_size = image_mem_size(ima);
+#endif
 
-                       for (ibuf = ima->ibufs.first; ibuf; ibuf = ibuf->next) {
-                               /* escape when image is painted on */
-                               if (ibuf->userflags & IB_BITMAPDIRTY)
-                                       break;
+                       IMB_moviecache_cleanup(ima->cache, imagecache_check_dirty, NULL);
 
-#if 0
-                               if (ibuf->mipmap[0])
-                                       totsize += 1.33 * ibuf->x * ibuf->y * 4;
-                               else
-                                       totsize += ibuf->x * ibuf->y * 4;
+#ifdef CHECK_FREED_SIZE
+                       tot_freed_size += old_size - image_mem_size(ima);
 #endif
-                       }
-                       if (ibuf == NULL)
-                               image_free_buffers(ima);
                }
        }
-       /* printf("freed total %d MB\n", totsize/(1024*1024)); */
+#ifdef CHECK_FREED_SIZE
+       printf("%s: freed total %lu MB\n", __func__, tot_freed_size / (1024 * 1024));
+#endif
+}
+
+static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void *userdata)
+{
+       int except_frame = *(int *)userdata;
+       return (ibuf->userflags & IB_BITMAPDIRTY) == 0 &&
+              (ibuf->index != IMA_NO_INDEX) &&
+              (except_frame != IMA_INDEX_FRAME(ibuf->index));
 }
 
 /* except_frame is weak, only works for seqs without offset... */
 void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
 {
-       ImBuf *ibuf, *nbuf;
-
-       for (ibuf = ima->ibufs.first; ibuf; ibuf = nbuf) {
-               nbuf = ibuf->next;
-               if (ibuf->userflags & IB_BITMAPDIRTY)
-                       continue;
-               if (ibuf->index == IMA_NO_INDEX)
-                       continue;
-               if (except_frame != IMA_INDEX_FRAME(ibuf->index)) {
-                       BLI_remlink(&ima->ibufs, ibuf);
-
-                       if (ibuf->userdata) {
-                               MEM_freeN(ibuf->userdata);
-                               ibuf->userdata = NULL;
-                       }
-                       IMB_freeImBuf(ibuf);
-               }
+       BLI_spin_lock(&image_spin);
+       if (ima->cache != NULL) {
+               IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame);
        }
+       BLI_spin_unlock(&image_spin);
 }
 
 void BKE_image_all_free_anim_ibufs(int cfra)
@@ -917,7 +1012,7 @@ void BKE_image_all_free_anim_ibufs(int cfra)
        Image *ima;
 
        for (ima = G.main->image.first; ima; ima = ima->id.next)
-               if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE))
+               if (BKE_image_is_animated(ima))
                        BKE_image_free_anim_ibufs(ima, cfra);
 }
 
@@ -937,7 +1032,7 @@ int BKE_imtype_to_ftype(const char imtype)
                return RADHDR;
 #endif
        else if (imtype == R_IMF_IMTYPE_PNG)
-               return PNG;
+               return PNG | 15;
 #ifdef WITH_DDS
        else if (imtype == R_IMF_IMTYPE_DDS)
                return DDS;
@@ -1007,7 +1102,7 @@ char BKE_ftype_to_imtype(const int ftype)
 }
 
 
-int BKE_imtype_is_movie(const char imtype)
+bool BKE_imtype_is_movie(const char imtype)
 {
        switch (imtype) {
                case R_IMF_IMTYPE_AVIRAW:
@@ -1018,9 +1113,9 @@ int BKE_imtype_is_movie(const char imtype)
                case R_IMF_IMTYPE_THEORA:
                case R_IMF_IMTYPE_XVID:
                case R_IMF_IMTYPE_FRAMESERVER:
-                       return 1;
+                       return true;
        }
-       return 0;
+       return false;
 }
 
 int BKE_imtype_supports_zbuf(const char imtype)
@@ -1085,6 +1180,7 @@ char BKE_imtype_valid_channels(const char imtype)
                case R_IMF_IMTYPE_QUICKTIME:
                case R_IMF_IMTYPE_DPX:
                        chan_flag |= IMA_CHAN_FLAG_ALPHA;
+                       break;
        }
 
        /* bw */
@@ -1096,6 +1192,7 @@ char BKE_imtype_valid_channels(const char imtype)
                case R_IMF_IMTYPE_TIFF:
                case R_IMF_IMTYPE_IRIS:
                        chan_flag |= IMA_CHAN_FLAG_BW;
+                       break;
        }
 
        return chan_flag;
@@ -1119,6 +1216,8 @@ char BKE_imtype_valid_depths(const char imtype)
                        return R_IMF_CHAN_DEPTH_10;
                case R_IMF_IMTYPE_JP2:
                        return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
+               case R_IMF_IMTYPE_PNG:
+                       return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
                /* most formats are 8bit only */
                default:
                        return R_IMF_CHAN_DEPTH_8;
@@ -1165,80 +1264,96 @@ char BKE_imtype_from_arg(const char *imtype_arg)
        else return R_IMF_IMTYPE_INVALID;
 }
 
-int BKE_add_image_extension(char *string, const char imtype)
+static bool do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format)
 {
        const char *extension = NULL;
+       const char *extension_test;
+       (void)im_format;  /* may be unused, depends on build options */
 
        if (imtype == R_IMF_IMTYPE_IRIS) {
-               if (!BLI_testextensie(string, ".rgb"))
-                       extension = ".rgb";
+               if (!BLI_testextensie(string, extension_test = ".rgb"))
+                       extension = extension_test;
        }
        else if (imtype == R_IMF_IMTYPE_IRIZ) {
-               if (!BLI_testextensie(string, ".rgb"))
-                       extension = ".rgb";
+               if (!BLI_testextensie(string, extension_test = ".rgb"))
+                       extension = extension_test;
        }
 #ifdef WITH_HDR
        else if (imtype == R_IMF_IMTYPE_RADHDR) {
-               if (!BLI_testextensie(string, ".hdr"))
-                       extension = ".hdr";
+               if (!BLI_testextensie(string, extension_test = ".hdr"))
+                       extension = extension_test;
        }
 #endif
        else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
-               if (!BLI_testextensie(string, ".png"))
-                       extension = ".png";
+               if (!BLI_testextensie(string, extension_test = ".png"))
+                       extension = extension_test;
        }
 #ifdef WITH_DDS
        else if (imtype == R_IMF_IMTYPE_DDS) {
-               if (!BLI_testextensie(string, ".dds"))
-                       extension = ".dds";
+               if (!BLI_testextensie(string, extension_test = ".dds"))
+                       extension = extension_test;
        }
 #endif
-       else if (imtype == R_IMF_IMTYPE_RAWTGA) {
-               if (!BLI_testextensie(string, ".tga"))
-                       extension = ".tga";
+       else if (ELEM(imtype, R_IMF_IMTYPE_TARGA, R_IMF_IMTYPE_RAWTGA)) {
+               if (!BLI_testextensie(string, extension_test = ".tga"))
+                       extension = extension_test;
        }
        else if (imtype == R_IMF_IMTYPE_BMP) {
-               if (!BLI_testextensie(string, ".bmp"))
-                       extension = ".bmp";
+               if (!BLI_testextensie(string, extension_test = ".bmp"))
+                       extension = extension_test;
        }
 #ifdef WITH_TIFF
        else if (imtype == R_IMF_IMTYPE_TIFF) {
-               if (!BLI_testextensie(string, ".tif") &&
-                   !BLI_testextensie(string, ".tiff"))
-               {
-                       extension = ".tif";
+               if (!BLI_testextensie_n(string, extension_test = ".tif", ".tiff", NULL)) {
+                       extension = extension_test;
                }
        }
 #endif
+#ifdef WITH_OPENIMAGEIO
+       else if (imtype == R_IMF_IMTYPE_PSD) {
+               if (!BLI_testextensie(string, extension_test = ".psd"))
+                       extension = extension_test;
+       }
+#endif
 #ifdef WITH_OPENEXR
        else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
-               if (!BLI_testextensie(string, ".exr"))
-                       extension = ".exr";
+               if (!BLI_testextensie(string, extension_test = ".exr"))
+                       extension = extension_test;
        }
 #endif
 #ifdef WITH_CINEON
        else if (imtype == R_IMF_IMTYPE_CINEON) {
-               if (!BLI_testextensie(string, ".cin"))
-                       extension = ".cin";
+               if (!BLI_testextensie(string, extension_test = ".cin"))
+                       extension = extension_test;
        }
        else if (imtype == R_IMF_IMTYPE_DPX) {
-               if (!BLI_testextensie(string, ".dpx"))
-                       extension = ".dpx";
+               if (!BLI_testextensie(string, extension_test = ".dpx"))
+                       extension = extension_test;
        }
 #endif
-       else if (imtype == R_IMF_IMTYPE_TARGA) {
-               if (!BLI_testextensie(string, ".tga"))
-                       extension = ".tga";
-       }
 #ifdef WITH_OPENJPEG
        else if (imtype == R_IMF_IMTYPE_JP2) {
-               if (!BLI_testextensie(string, ".jp2"))
-                       extension = ".jp2";
+               if (im_format) {
+                       if (im_format->jp2_codec == R_IMF_JP2_CODEC_JP2) {
+                               if (!BLI_testextensie(string, extension_test = ".jp2"))
+                                       extension = extension_test;
+                       }
+                       else if (im_format->jp2_codec == R_IMF_JP2_CODEC_J2K) {
+                               if (!BLI_testextensie(string, extension_test = ".j2c"))
+                                       extension = extension_test;
+                       }
+                       else
+                               BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec");
+               }
+               else {
+                       if (!BLI_testextensie(string, extension_test = ".jp2"))
+                               extension = extension_test;
+               }
        }
 #endif
        else { //   R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90, R_IMF_IMTYPE_QUICKTIME etc
-               if (!(BLI_testextensie(string, ".jpg") || BLI_testextensie(string, ".jpeg")))
-                       extension = ".jpg";
+               if (!(BLI_testextensie_n(string, extension_test = ".jpg", ".jpeg", NULL)))
+                       extension = extension_test;
        }
 
        if (extension) {
@@ -1259,13 +1374,24 @@ int BKE_add_image_extension(char *string, const char imtype)
        }
 }
 
+int BKE_add_image_extension(char *string, const ImageFormatData *im_format)
+{
+       return do_add_image_extension(string, im_format->imtype, im_format);
+}
+
+int BKE_add_image_extension_from_type(char *string, const char imtype)
+{
+       return do_add_image_extension(string, imtype, NULL);
+}
+
 void BKE_imformat_defaults(ImageFormatData *im_format)
 {
        memset(im_format, 0, sizeof(*im_format));
-       im_format->planes = R_IMF_PLANES_RGB;
+       im_format->planes = R_IMF_PLANES_RGBA;
        im_format->imtype = R_IMF_IMTYPE_PNG;
+       im_format->depth = R_IMF_CHAN_DEPTH_8;
        im_format->quality = 90;
-       im_format->compress = 90;
+       im_format->compress = 15;
 
        BKE_color_managed_display_settings_init(&im_format->display_settings);
        BKE_color_managed_view_settings_init(&im_format->view_settings);
@@ -1288,9 +1414,13 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
                im_format->imtype = R_IMF_IMTYPE_RADHDR;
 #endif
 
-       else if (ftype == PNG)
+       else if (ftype == PNG) {
                im_format->imtype = R_IMF_IMTYPE_PNG;
 
+               if (custom_flags & PNG_16BIT)
+                       im_format->depth = R_IMF_CHAN_DEPTH_16;
+       }
+
 #ifdef WITH_DDS
        else if (ftype == DDS)
                im_format->imtype = R_IMF_IMTYPE_DDS;
@@ -1351,6 +1481,13 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
                        if (ftype & JP2_CINE_48FPS)
                                im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_48;
                }
+
+               if (ftype & JP2_JP2)
+                       im_format->jp2_codec = R_IMF_JP2_CODEC_JP2;
+               else if (ftype & JP2_J2K)
+                       im_format->jp2_codec = R_IMF_JP2_CODEC_J2K;
+               else
+                       BLI_assert(!"Unsupported jp2 codec was specified in file type");
        }
 #endif
 
@@ -1360,6 +1497,12 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
        }
 
        /* planes */
+       /* TODO(sergey): Channels doesn't correspond actual planes used for image buffer
+        *               For example byte buffer will have 4 channels but it might easily
+        *               be BW or RGB image.
+        *
+        *               Need to use im_format->planes = imbuf->planes instead?
+        */
        switch (imbuf->channels) {
                case 0:
                case 4: im_format->planes = R_IMF_PLANES_RGBA;
@@ -1374,30 +1517,6 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
 
 }
 
-static void timecode_simple_string(char *text, size_t text_size, const int cfra, int const frs_sec)
-{
-       int f = (int)(cfra % frs_sec);
-       int s = (int)(cfra / frs_sec);
-       int h = 0;
-       int m = 0;
-
-       if (s) {
-               m = (int)(s / 60);
-               s %= 60;
-
-               if (m) {
-                       h = (int)(m / 60);
-                       m %= 60;
-               }
-       }
-
-       if (frs_sec < 100) {
-               BLI_snprintf(text, text_size, "%02d:%02d:%02d.%02d", h, m, s, f);
-       }
-       else {
-               BLI_snprintf(text, text_size, "%02d:%02d:%02d.%03d", h, m, s, f);
-       }
-}
 
 #define STAMP_NAME_SIZE ((MAX_ID_NAME - 2) + 16)
 /* could allow access externally - 512 is for long names,
@@ -1461,8 +1580,9 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
        }
 
        if (scene->r.stamp & R_STAMP_TIME) {
-               timecode_simple_string(text, sizeof(text), scene->r.cfra, scene->r.frs_sec);
-               BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), do_prefix ? "Time %s" : "%s", text);
+               const short timecode_style = USER_TIMECODE_SMPTE_FULL;
+               BLI_timecode_string_from_time(text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style);
+               BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), do_prefix ? "Timecode %s" : "%s", text);
        }
        else {
                stamp_data->time[0] = '\0';
@@ -1493,7 +1613,9 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
                if (camera && camera->type == OB_CAMERA) {
                        BLI_snprintf(text, sizeof(text), "%.2f", ((Camera *)camera->data)->lens);
                }
-               else BLI_strncpy(text, "<none>", sizeof(text));
+               else {
+                       BLI_strncpy(text, "<none>", sizeof(text));
+               }
 
                BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), do_prefix ? "Lens %s" : "%s", text);
        }
@@ -1525,7 +1647,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
                RenderStats *stats = re ? RE_GetStats(re) : NULL;
 
                if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) {
-                       BLI_timestr(stats->lastframetime, text);
+                       BLI_timestr(stats->lastframetime, text, sizeof(text));
 
                        BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), do_prefix ? "RenderTime %s" : "%s", text);
                }
@@ -1548,6 +1670,9 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        /* this could be an argument if we want to operate on non linear float imbuf's
         * for now though this is only used for renders which use scene settings */
 
+#define TEXT_SIZE_CHECK(str, w, h) \
+       ((str[0]) && ((void)(h = h_fixed), (w = BLF_width(mono, str, sizeof(str)))))
+
 #define BUFF_MARGIN_X 2
 #define BUFF_MARGIN_Y 1
 
@@ -1577,9 +1702,8 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        x = 0;
        y = height;
 
-       if (stamp_data.file[0]) {
+       if (TEXT_SIZE_CHECK(stamp_data.file, w, h)) {
                /* Top left corner */
-               BLF_width_and_height(mono, stamp_data.file, &w, &h); h = h_fixed;
                y -= h;
 
                /* also a little of space to the background. */
@@ -1595,8 +1719,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        }
 
        /* Top left corner, below File */
-       if (stamp_data.note[0]) {
-               BLF_width_and_height(mono, stamp_data.note, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.note, w, h)) {
                y -= h;
 
                /* and space for background. */
@@ -1611,8 +1734,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        }
 
        /* Top left corner, below File (or Note) */
-       if (stamp_data.date[0]) {
-               BLF_width_and_height(mono, stamp_data.date, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.date, w, h)) {
                y -= h;
 
                /* and space for background. */
@@ -1627,8 +1749,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        }
 
        /* Top left corner, below File, Date or Note */
-       if (stamp_data.rendertime[0]) {
-               BLF_width_and_height(mono, stamp_data.rendertime, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.rendertime, w, h)) {
                y -= h;
 
                /* and space for background. */
@@ -1643,8 +1764,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        y = 0;
 
        /* Bottom left corner, leaving space for timing */
-       if (stamp_data.marker[0]) {
-               BLF_width_and_height(mono, stamp_data.marker, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.marker, w, h)) {
 
                /* extra space for background. */
                buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp,  display,
@@ -1659,8 +1779,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        }
 
        /* Left bottom corner */
-       if (stamp_data.time[0]) {
-               BLF_width_and_height(mono, stamp_data.time, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.time, w, h)) {
 
                /* extra space for background */
                buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
@@ -1674,8 +1793,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
                x += w + pad;
        }
 
-       if (stamp_data.frame[0]) {
-               BLF_width_and_height(mono, stamp_data.frame, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.frame, w, h)) {
 
                /* extra space for background. */
                buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
@@ -1689,8 +1807,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
                x += w + pad;
        }
 
-       if (stamp_data.camera[0]) {
-               BLF_width_and_height(mono, stamp_data.camera, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.camera, w, h)) {
 
                /* extra space for background. */
                buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
@@ -1702,8 +1819,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
                x += w + pad;
        }
 
-       if (stamp_data.cameralens[0]) {
-               BLF_width_and_height(mono, stamp_data.cameralens, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.cameralens, w, h)) {
 
                /* extra space for background. */
                buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
@@ -1712,8 +1828,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
                BLF_draw_buffer(mono, stamp_data.cameralens);
        }
 
-       if (stamp_data.scene[0]) {
-               BLF_width_and_height(mono, stamp_data.scene, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) {
 
                /* Bottom right corner, with an extra space because blenfont is too strict! */
                x = width - w - 2;
@@ -1727,8 +1842,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
                BLF_draw_buffer(mono, stamp_data.scene);
        }
 
-       if (stamp_data.strip[0]) {
-               BLF_width_and_height(mono, stamp_data.strip, &w, &h); h = h_fixed;
+       if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) {
 
                /* Top right corner, with an extra space because blenfont is too strict! */
                x = width - w - pad;
@@ -1743,8 +1857,9 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
        }
 
        /* cleanup the buffer. */
-       BLF_buffer(mono, NULL, NULL, 0, 0, 0, FALSE);
+       BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
 
+#undef TEXT_SIZE_CHECK
 #undef BUFF_MARGIN_X
 #undef BUFF_MARGIN_Y
 }
@@ -1771,7 +1886,7 @@ void BKE_imbuf_stamp_info(Scene *scene, Object *camera, struct ImBuf *ibuf)
        if (stamp_data.rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data.rendertime);
 }
 
-int BKE_imbuf_alpha_test(ImBuf *ibuf)
+bool BKE_imbuf_alpha_test(ImBuf *ibuf)
 {
        int tot;
        if (ibuf->rect_float) {
@@ -1815,8 +1930,12 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
        else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
                ibuf->ftype = PNG;
 
-               if (imtype == R_IMF_IMTYPE_PNG)
+               if (imtype == R_IMF_IMTYPE_PNG) {
+                       if (imf->depth == R_IMF_CHAN_DEPTH_16)
+                               ibuf->ftype |= PNG_16BIT;
+
                        ibuf->ftype |= compress;
+               }
 
        }
 #ifdef WITH_DDS
@@ -1866,7 +1985,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
        else if (imtype == R_IMF_IMTYPE_DPX) {
                ibuf->ftype = DPX;
                if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
-                 ibuf->ftype |= CINEON_LOG;
+                       ibuf->ftype |= CINEON_LOG;
                }
                if (imf->depth == R_IMF_CHAN_DEPTH_16) {
                        ibuf->ftype |= CINEON_16BIT;
@@ -1906,6 +2025,13 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
                        if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_48)
                                ibuf->ftype |= JP2_CINE_48FPS;
                }
+
+               if (imf->jp2_codec == R_IMF_JP2_CODEC_JP2)
+                       ibuf->ftype |= JP2_JP2;
+               else if (imf->jp2_codec == R_IMF_JP2_CODEC_J2K)
+                       ibuf->ftype |= JP2_J2K;
+               else
+                       BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec");
        }
 #endif
        else {
@@ -1956,7 +2082,8 @@ int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, cons
 }
 
 
-void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames)
+static void do_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype,
+                             const ImageFormatData *im_format, const short use_ext, const short use_frames)
 {
        if (string == NULL) return;
        BLI_strncpy(string, base, FILE_MAX - 10);   /* weak assumption */
@@ -1966,8 +2093,17 @@ void BKE_makepicstring(char *string, const char *base, const char *relbase, int
                BLI_path_frame(string, frame, 4);
 
        if (use_ext)
-               BKE_add_image_extension(string, imtype);
+               do_add_image_extension(string, imtype, im_format);
+}
 
+void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const ImageFormatData *im_format, const short use_ext, const short use_frames)
+{
+       do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames);
+}
+
+void BKE_makepicstring_from_type(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames)
+{
+       do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames);
 }
 
 /* used by sequencer too */
@@ -2026,7 +2162,7 @@ Image *BKE_image_verify_viewer(int type, const char *name)
                                break;
 
        if (ima == NULL)
-               ima = image_alloc(name, IMA_SRC_VIEWER, type);
+               ima = image_alloc(G.main, name, IMA_SRC_VIEWER, type);
 
        /* happens on reload, imagewindow cannot be image user when hidden*/
        if (ima->id.us == 0)
@@ -2050,9 +2186,7 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
        /* texture users */
        for (tex = mainp->tex.first; tex; tex = tex->id.next) {
                if (tex->type == TEX_IMAGE && tex->ima) {
-                       if (ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
-                               callback(tex->ima, &tex->iuser, customdata);
-                       }
+                       callback(tex->ima, &tex->iuser, customdata);
                }
        }
 
@@ -2074,7 +2208,7 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
                                }
                                else if (sa->spacetype == SPACE_NODE) {
                                        SpaceNode *snode = sa->spacedata.first;
-                                       if ((snode->treetype == NTREE_COMPOSIT) && (snode->nodetree)) {
+                                       if (snode->nodetree && snode->nodetree->type == NTREE_COMPOSIT) {
                                                bNode *node;
                                                for (node = snode->nodetree->nodes.first; node; node = node->next) {
                                                        if (node->id && node->type == CMP_NODE_IMAGE) {
@@ -2094,7 +2228,7 @@ static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdat
 {
        Image *changed_image = customdata;
 
-       if (ima == changed_image) {
+       if (ima == changed_image && BKE_image_is_animated(ima)) {
                iuser->flag |= IMA_NEED_FRAME_RECALC;
        }
 }
@@ -2119,17 +2253,38 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
 
                        if (ima->source == IMA_SRC_GENERATED) {
                                if (ima->gen_x == 0 || ima->gen_y == 0) {
-                                       ImBuf *ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0);
+                                       ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
                                        if (ibuf) {
                                                ima->gen_x = ibuf->x;
                                                ima->gen_y = ibuf->y;
+                                               IMB_freeImBuf(ibuf);
                                        }
                                }
+
+                               /* Changing source type to generated will likely change file format
+                                * used by generated image buffer. Saving different file format to
+                                * the old name might confuse other applications.
+                                *
+                                * Here we ensure original image path wouldn't be used when saving
+                                * generated image.
+                                */
+                               ima->name[0] = '\0';
                        }
 
+#if 0
                        /* force reload on first use, but not for multilayer, that makes nodes and buttons in ui drawing fail */
                        if (ima->type != IMA_TYPE_MULTILAYER)
                                image_free_buffers(ima);
+#else
+                       /* image buffers for non-sequence multilayer will share buffers with RenderResult,
+                        * however sequence multilayer will own buffers. Such logic makes switching from
+                        * single multilayer file to sequence completely unstable
+                        * since changes in nodes seems this workaround isn't needed anymore, all sockets
+                        * are nicely detecting anyway, but freeing buffers always here makes multilayer
+                        * sequences behave stable
+                        */
+                       image_free_buffers(ima);
+#endif
 
                        ima->ok = 1;
                        if (iuser)
@@ -2284,7 +2439,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima)
 static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
 {
        const char *colorspace = ima->colorspace_settings.name;
-       int predivide = ima->flag & IMA_CM_PREDIVIDE;
+       int predivide = ima->alpha_mode == IMA_ALPHA_PREMUL;
 
        ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
 
@@ -2316,6 +2471,18 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
 
 }
 
+static int imbuf_alpha_flags_for_image(Image *ima)
+{
+       int flag = 0;
+
+       if (ima->flag & IMA_IGNORE_ALPHA)
+               flag |= IB_ignore_alpha;
+       else if (ima->alpha_mode == IMA_ALPHA_PREMUL)
+               flag |= IB_alphamode_premul;
+
+       return flag;
+}
+
 static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
 {
        struct ImBuf *ibuf;
@@ -2330,8 +2497,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
        BKE_image_user_file_path(iuser, ima, name);
 
        flag = IB_rect | IB_multilayer;
-       if (ima->flag & IMA_DO_PREMUL)
-               flag |= IB_premul;
+       flag |= imbuf_alpha_flags_for_image(ima);
 
        /* read ibuf */
        ibuf = IMB_loadiffname(name, flag, ima->colorspace_settings.name);
@@ -2380,26 +2546,22 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
 
        /* check for new RenderResult */
        if (ima->rr == NULL || frame != ima->rr->framenr) {
-               /* copy to survive not found multilayer image */
-               RenderResult *oldrr = ima->rr;
+               if (ima->rr) {
+                       /* Cached image buffers shares pointers with render result,
+                        * need to ensure there's no image buffers are hanging around
+                        * with dead links after freeing the render result.
+                        */
+                       image_free_cahced_frames(ima);
+                       RE_FreeRenderResult(ima->rr);
+                       ima->rr = NULL;
+               }
 
-               ima->rr = NULL;
                ibuf = image_load_sequence_file(ima, iuser, frame);
 
                if (ibuf) { /* actually an error */
                        ima->type = IMA_TYPE_IMAGE;
                        printf("error, multi is normal image\n");
                }
-               // printf("loaded new result %p\n", ima->rr);
-               /* free result if new one found */
-               if (ima->rr) {
-                       // if (oldrr) printf("freed previous result %p\n", oldrr);
-                       if (oldrr) RE_FreeRenderResult(oldrr);
-               }
-               else {
-                       ima->rr = oldrr;
-               }
-
        }
        if (ima->rr) {
                RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
@@ -2490,15 +2652,14 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
        /* is there a PackedFile with this image ? */
        if (ima->packedfile) {
                flag = IB_rect | IB_multilayer;
-               if (ima->flag & IMA_DO_PREMUL) flag |= IB_premul;
+               flag |= imbuf_alpha_flags_for_image(ima);
 
                ibuf = IMB_ibImageFromMemory((unsigned char *)ima->packedfile->data, ima->packedfile->size, flag,
                                             ima->colorspace_settings.name, "<packed data>");
        }
        else {
                flag = IB_rect | IB_multilayer | IB_metadata;
-               if (ima->flag & IMA_DO_PREMUL)
-                       flag |= IB_premul;
+               flag |= imbuf_alpha_flags_for_image(ima);
 
                /* get the right string */
                BKE_image_user_frame_calc(iuser, cfra, 0);
@@ -2589,6 +2750,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
        int channels, layer, pass;
        ImBuf *ibuf;
        int from_render = (ima->render_slot == ima->last_render_slot);
+       bool byte_buffer_in_display_space = false;
 
        if (!(iuser && iuser->scene))
                return NULL;
@@ -2600,8 +2762,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
        re = RE_GetRender(iuser->scene->id.name);
 
        channels = 4;
-       layer = (iuser) ? iuser->layer : 0;
-       pass = (iuser) ? iuser->pass : 0;
+       layer = iuser->layer;
+       pass = iuser->pass;
 
        if (from_render) {
                RE_AcquireResultImage(re, &rres);
@@ -2635,6 +2797,14 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
        if (rres.have_combined && layer == 0) {
                /* pass */
        }
+       else if (rect && layer == 0) {
+               /* rect32 is set when there's a Sequence pass, this pass seems
+                * to have layer=0 (this is from image_buttons.c)
+                * in this case we ignore float buffer, because it could have
+                * hung from previous pass which was float
+                */
+               rectf = NULL;
+       }
        else if (rres.layers.first) {
                RenderLayer *rl = BLI_findlink(&rres.layers, layer - (rres.have_combined ? 1 : 0));
                if (rl) {
@@ -2643,6 +2813,13 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
                        /* there's no combined pass, is in renderlayer itself */
                        if (pass == 0) {
                                rectf = rl->rectf;
+                               if (rectf == NULL) {
+                                       /* Happens when Save Buffers is enabled.
+                                        * Use display buffer stored in the render layer.
+                                        */
+                                       rect = (unsigned int *) rl->display_buffer;
+                                       byte_buffer_in_display_space = true;
+                               }
                        }
                        else {
                                rpass = BLI_findlink(&rl->passes, pass - 1);
@@ -2659,7 +2836,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
                }
        }
 
-       ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0);
+       ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
 
        /* make ibuf if needed, and initialize it */
        if (ibuf == NULL) {
@@ -2667,6 +2844,27 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
                image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
        }
 
+       /* Set color space settings for a byte buffer.
+        *
+        * This is mainly to make it so color management treats byte buffer
+        * from render result with Save Buffers enabled as final display buffer
+        * and doesnt' apply any color management on it.
+        *
+        * For other cases we need to be sure it stays to default byte buffer space.
+        */
+       if (ibuf->rect != rect) {
+               if (byte_buffer_in_display_space) {
+                       const char *colorspace =
+                               IMB_colormanagement_get_display_colorspace_name(&iuser->scene->view_settings,
+                                                                           &iuser->scene->display_settings);
+                       IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
+               }
+               else {
+                       const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
+                       IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
+               }
+       }
+
        /* invalidate color managed buffers if render result changed */
        BLI_lock_thread(LOCK_COLORMANAGE);
        if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->rect_float != rectf) {
@@ -2676,13 +2874,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
        ibuf->x = rres.rectx;
        ibuf->y = rres.recty;
 
-       /* free rect buffer if float buffer changes, so it can be recreated with
-        * the updated result, and also in case we got byte buffer from sequencer,
-        * so we don't keep reference to freed buffer */
-       if (ibuf->rect_float != rectf || rect)
-               imb_freerectImBuf(ibuf);
-
        if (rect) {
+               imb_freerectImBuf(ibuf);
                ibuf->rect = rect;
        }
        else {
@@ -2718,21 +2911,40 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
 
        ibuf->dither = dither;
 
-       if (iuser->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE) {
-               ibuf->flags |= IB_cm_predivide;
-               ima->flag |= IMA_CM_PREDIVIDE;
-       }
-       else {
-               ibuf->flags &= ~IB_cm_predivide;
-               ima->flag &= ~IMA_CM_PREDIVIDE;
-       }
-
        ima->ok = IMA_OK_LOADED;
 
        return ibuf;
 }
 
-static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame_r, int *index_r)
+static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
+{
+       int frame = 0, index = 0;
+
+       /* see if we already have an appropriate ibuf, with image source and type */
+       if (ima->source == IMA_SRC_MOVIE) {
+               frame = iuser ? iuser->framenr : ima->lastframe;
+       }
+       else if (ima->source == IMA_SRC_SEQUENCE) {
+               if (ima->type == IMA_TYPE_IMAGE) {
+                       frame = iuser ? iuser->framenr : ima->lastframe;
+               }
+               else if (ima->type == IMA_TYPE_MULTILAYER) {
+                       frame = iuser ? iuser->framenr : ima->lastframe;
+                       index = iuser ? iuser->multi_index : IMA_NO_INDEX;
+               }
+       }
+
+       *r_frame = frame;
+       *r_index = index;
+}
+
+/* Get the ibuf from an image cache for a given image user.
+ *
+ * Returns referenced image buffer if it exists, callee is to
+ * call IMB_freeImBuf to de-reference the image buffer after
+ * it's done handling it.
+ */
+static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
 {
        ImBuf *ibuf = NULL;
        int frame = 0, index = 0;
@@ -2740,7 +2952,7 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame
        /* see if we already have an appropriate ibuf, with image source and type */
        if (ima->source == IMA_SRC_MOVIE) {
                frame = iuser ? iuser->framenr : ima->lastframe;
-               ibuf = image_get_ibuf(ima, 0, frame);
+               ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
                /* XXX temp stuff? */
                if (ima->lastframe != frame)
                        ima->tpageflag |= IMA_TPAGE_REFRESH;
@@ -2749,7 +2961,7 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame
        else if (ima->source == IMA_SRC_SEQUENCE) {
                if (ima->type == IMA_TYPE_IMAGE) {
                        frame = iuser ? iuser->framenr : ima->lastframe;
-                       ibuf = image_get_ibuf(ima, 0, frame);
+                       ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
 
                        /* XXX temp stuff? */
                        if (ima->lastframe != frame) {
@@ -2760,17 +2972,17 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame
                else if (ima->type == IMA_TYPE_MULTILAYER) {
                        frame = iuser ? iuser->framenr : ima->lastframe;
                        index = iuser ? iuser->multi_index : IMA_NO_INDEX;
-                       ibuf = image_get_ibuf(ima, index, frame);
+                       ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
                }
        }
        else if (ima->source == IMA_SRC_FILE) {
                if (ima->type == IMA_TYPE_IMAGE)
-                       ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0);
+                       ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
                else if (ima->type == IMA_TYPE_MULTILAYER)
-                       ibuf = image_get_ibuf(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
+                       ibuf = image_get_cached_ibuf_for_index_frame(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
        }
        else if (ima->source == IMA_SRC_GENERATED) {
-               ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0);
+               ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
        }
        else if (ima->source == IMA_SRC_VIEWER) {
                /* always verify entirely, not that this shouldn't happen
@@ -2778,15 +2990,30 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame
                 * a big bottleneck */
        }
 
-       if (frame_r)
-               *frame_r = frame;
+       if (r_frame)
+               *r_frame = frame;
 
-       if (index_r)
-               *index_r = index;
+       if (r_index)
+               *r_index = index;
 
        return ibuf;
 }
 
+BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
+{
+       if (ima == NULL)
+               return FALSE;
+
+       if (iuser) {
+               if (iuser->ok == 0)
+                       return FALSE;
+       }
+       else if (ima->ok == 0)
+               return FALSE;
+
+       return TRUE;
+}
+
 /* Checks optional ImageUser and verifies/creates ImBuf.
  *
  * not thread-safe, so callee should worry about thread locks
@@ -2801,17 +3028,10 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
                *lock_r = NULL;
 
        /* quick reject tests */
-       if (ima == NULL)
-               return NULL;
-
-       if (iuser) {
-               if (iuser->ok == 0)
-                       return NULL;
-       }
-       else if (ima->ok == 0)
+       if (!image_quick_test(ima, iuser))
                return NULL;
 
-       ibuf = image_get_ibuf_threadsafe(ima, iuser, &frame, &index);
+       ibuf = image_get_cached_ibuf(ima, iuser, &frame, &index);
 
        if (ibuf == NULL) {
                /* we are sure we have to load the ibuf, using source and type */
@@ -2845,7 +3065,8 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
                        /* UV testgrid or black or solid etc */
                        if (ima->gen_x == 0) ima->gen_x = 1024;
                        if (ima->gen_y == 0) ima->gen_y = 1024;
-                       ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 24, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type,
+                       if (ima->gen_depth == 0) ima->gen_depth = 24;
+                       ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_depth, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type,
                                             color, &ima->colorspace_settings);
                        image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
                        ima->ok = IMA_OK_LOADED;
@@ -2855,6 +3076,9 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
                                /* always verify entirely, and potentially
                                 * returns pointer to release later */
                                ibuf = image_get_render_result(ima, iuser, lock_r);
+                               if (ibuf) {
+                                       ibuf->userflags |= IB_PERSISTENT;
+                               }
                        }
                        else if (ima->type == IMA_TYPE_COMPOSITE) {
                                /* requires lock/unlock, otherwise don't return image */
@@ -2864,8 +3088,8 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
                                        *lock_r = ima;
 
                                        /* XXX anim play for viewer nodes not yet supported */
-                                       frame = 0; // XXX iuser?iuser->framenr:0;
-                                       ibuf = image_get_ibuf(ima, 0, frame);
+                                       frame = 0; // XXX iuser ? iuser->framenr : 0;
+                                       ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
 
                                        if (!ibuf) {
                                                /* Composite Viewer, all handled in compositor */
@@ -2873,6 +3097,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
                                                ibuf = IMB_allocImBuf(256, 256, 32, IB_rect);
                                                image_assign_ibuf(ima, ibuf, 0, frame);
                                        }
+                                       ibuf->userflags |= IB_PERSISTENT;
                                }
                        }
                }
@@ -2898,9 +3123,6 @@ ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
 
        ibuf = image_acquire_ibuf(ima, iuser, lock_r);
 
-       if (ibuf)
-               IMB_refImBuf(ibuf);
-
        BLI_spin_unlock(&image_spin);
 
        return ibuf;
@@ -2927,38 +3149,142 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
 }
 
 /* checks whether there's an image buffer for given image and user */
-int BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
+bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
 {
        ImBuf *ibuf;
 
        /* quick reject tests */
-       if (ima == NULL)
+       if (!image_quick_test(ima, iuser))
                return FALSE;
 
-       if (iuser) {
-               if (iuser->ok == 0)
-                       return FALSE;
+       BLI_spin_lock(&image_spin);
+
+       ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL);
+
+       if (!ibuf)
+               ibuf = image_acquire_ibuf(ima, iuser, NULL);
+
+       BLI_spin_unlock(&image_spin);
+
+       IMB_freeImBuf(ibuf);
+
+       return ibuf != NULL;
+}
+
+/* ******** Pool for image buffers ********  */
+
+typedef struct ImagePoolEntry {
+       struct ImagePoolEntry *next, *prev;
+       Image *image;
+       ImBuf *ibuf;
+       int index;
+       int frame;
+} ImagePoolEntry;
+
+typedef struct ImagePool {
+       ListBase image_buffers;
+} ImagePool;
+
+ImagePool *BKE_image_pool_new(void)
+{
+       ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
+
+       return pool;
+}
+
+void BKE_image_pool_free(ImagePool *pool)
+{
+       ImagePoolEntry *entry, *next_entry;
+
+       /* use single lock to dereference all the image buffers */
+       BLI_spin_lock(&image_spin);
+
+       for (entry = pool->image_buffers.first; entry; entry = next_entry) {
+               next_entry = entry->next;
+
+               if (entry->ibuf)
+                       IMB_freeImBuf(entry->ibuf);
+
+               MEM_freeN(entry);
        }
-       else if (ima->ok == 0)
-               return FALSE;
 
-       ibuf = image_get_ibuf_threadsafe(ima, iuser, NULL, NULL);
+       BLI_spin_unlock(&image_spin);
 
-       if (!ibuf) {
-               BLI_spin_lock(&image_spin);
+       MEM_freeN(pool);
+}
 
-               ibuf = image_get_ibuf_threadsafe(ima, iuser, NULL, NULL);
+BLI_INLINE ImBuf *image_pool_find_entry(ImagePool *pool, Image *image, int frame, int index, int *found)
+{
+       ImagePoolEntry *entry;
 
-               if (!ibuf)
-                       ibuf = image_acquire_ibuf(ima, iuser, NULL);
+       *found = FALSE;
 
-               BLI_spin_unlock(&image_spin);
+       for (entry = pool->image_buffers.first; entry; entry = entry->next) {
+               if (entry->image == image && entry->frame == frame && entry->index == index) {
+                       *found = TRUE;
+                       return entry->ibuf;
+               }
        }
 
-       return ibuf != NULL;
+       return NULL;
 }
 
-int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, short *r_is_in_range)
+ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
+{
+       ImBuf *ibuf;
+       int index, frame, found;
+
+       if (!image_quick_test(ima, iuser))
+               return NULL;
+
+       if (pool == NULL) {
+               /* pool could be NULL, in this case use general acquire function */
+               return BKE_image_acquire_ibuf(ima, iuser, NULL);
+       }
+
+       image_get_frame_and_index(ima, iuser, &frame, &index);
+
+       ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+       if (found)
+               return ibuf;
+
+       BLI_spin_lock(&image_spin);
+
+       ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+
+       /* will also create entry even in cases image buffer failed to load,
+        * prevents trying to load the same buggy file multiple times
+        */
+       if (!found) {
+               ImagePoolEntry *entry;
+
+               ibuf = image_acquire_ibuf(ima, iuser, NULL);
+
+               entry = MEM_callocN(sizeof(ImagePoolEntry), "Image Pool Entry");
+               entry->image = ima;
+               entry->frame = frame;
+               entry->index = index;
+               entry->ibuf = ibuf;
+
+               BLI_addtail(&pool->image_buffers, entry);
+       }
+
+       BLI_spin_unlock(&image_spin);
+
+       return ibuf;
+}
+
+void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
+{
+       /* if pool wasn't actually used, use general release stuff,
+        * for pools image buffers will be dereferenced on pool free
+        */
+       if (pool == NULL) {
+               BKE_image_release_ibuf(ima, ibuf, NULL);
+       }
+}
+
+int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool *r_is_in_range)
 {
        const int len = (iuser->fie_ima * iuser->frames) / 2;
 
@@ -3020,7 +3346,7 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, shor
 void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
 {
        if (iuser) {
-               short is_in_range;
+               bool is_in_range;
                const int framenr = BKE_image_user_frame_get(iuser, cfra, fieldnr, &is_in_range);
 
                if (is_in_range) {
@@ -3049,6 +3375,19 @@ void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
        }
 }
 
+/* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
+static void image_update_frame(struct Image *UNUSED(ima), struct ImageUser *iuser, void *customdata)
+{
+       int cfra = *(int *)customdata;
+
+       BKE_image_user_check_frame_calc(iuser, cfra, 0);
+}
+
+void BKE_image_update_frame(const Main *bmain, int cfra)
+{
+       BKE_image_walk_all_users(bmain, &cfra, image_update_frame);
+}
+
 void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
 {
        BLI_strncpy(filepath, ima->name, FILE_MAX);
@@ -3065,7 +3404,7 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
        BLI_path_abs(filepath, ID_BLEND_PATH(G.main, &ima->id));
 }
 
-int BKE_image_has_alpha(struct Image *image)
+bool BKE_image_has_alpha(struct Image *image)
 {
        ImBuf *ibuf;
        void *lock;
@@ -3120,3 +3459,200 @@ void BKE_image_get_aspect(Image *image, float *aspx, float *aspy)
        else
                *aspy = 1.0f;
 }
+
+unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame)
+{
+       ImageUser iuser = {NULL};
+       void *lock;
+       ImBuf *ibuf;
+       unsigned char *pixels = NULL;
+
+       iuser.framenr = frame;
+       iuser.ok = TRUE;
+
+       ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+       if (ibuf) {
+               pixels = (unsigned char *) ibuf->rect;
+
+               if (pixels)
+                       pixels = MEM_dupallocN(pixels);
+
+               BKE_image_release_ibuf(image, ibuf, lock);
+       }
+
+       if (!pixels)
+               return NULL;
+
+       return pixels;
+}
+
+float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame)
+{
+       ImageUser iuser = {NULL};
+       void *lock;
+       ImBuf *ibuf;
+       float *pixels = NULL;
+
+       iuser.framenr = frame;
+       iuser.ok = TRUE;
+
+       ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+       if (ibuf) {
+               pixels = ibuf->rect_float;
+
+               if (pixels)
+                       pixels = MEM_dupallocN(pixels);
+
+               BKE_image_release_ibuf(image, ibuf, lock);
+       }
+
+       if (!pixels)
+               return NULL;
+
+       return pixels;
+}
+
+int BKE_image_sequence_guess_offset(Image *image)
+{
+       unsigned short numlen;
+       char head[FILE_MAX], tail[FILE_MAX];
+       char num[FILE_MAX] = {0};
+
+       BLI_stringdec(image->name, head, tail, &numlen);
+       BLI_strncpy(num, image->name + strlen(head), numlen + 1);
+
+       return atoi(num);
+}
+
+/**
+ * Checks the image buffer changes (not keyframed values)
+ *
+ * to see if we need to call #BKE_image_user_check_frame_calc
+ */
+bool BKE_image_is_animated(Image *image)
+{
+       return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
+}
+
+bool BKE_image_is_dirty(Image *image)
+{
+       bool is_dirty = false;
+
+       BLI_spin_lock(&image_spin);
+       if (image->cache != NULL) {
+               struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+
+               while (!IMB_moviecacheIter_done(iter)) {
+                       ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+                       if (ibuf->userflags & IB_BITMAPDIRTY) {
+                               is_dirty = true;
+                               break;
+                       }
+                       IMB_moviecacheIter_step(iter);
+               }
+               IMB_moviecacheIter_free(iter);
+       }
+       BLI_spin_unlock(&image_spin);
+
+       return is_dirty;
+}
+
+void BKE_image_file_format_set(Image *image, int ftype)
+{
+#if 0
+       ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+       if (ibuf) {
+               ibuf->ftype = ftype;
+       }
+       BKE_image_release_ibuf(image, ibuf, NULL);
+#endif
+
+       BLI_spin_lock(&image_spin);
+       if (image->cache != NULL) {
+               struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+
+               while (!IMB_moviecacheIter_done(iter)) {
+                       ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+                       ibuf->ftype = ftype;
+                       IMB_moviecacheIter_step(iter);
+               }
+               IMB_moviecacheIter_free(iter);
+       }
+       BLI_spin_unlock(&image_spin);
+}
+
+bool BKE_image_has_loaded_ibuf(Image *image)
+{
+       bool has_loaded_ibuf = false;
+
+       BLI_spin_lock(&image_spin);
+       if (image->cache != NULL) {
+               struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+
+               while (!IMB_moviecacheIter_done(iter)) {
+                       has_loaded_ibuf = true;
+                       break;
+               }
+               IMB_moviecacheIter_free(iter);
+       }
+       BLI_spin_unlock(&image_spin);
+
+       return has_loaded_ibuf;
+}
+
+/* References the result, BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling BKE_image_release_ibuf().
+ */
+ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
+{
+       ImBuf *ibuf = NULL;
+
+       BLI_spin_lock(&image_spin);
+       if (image->cache != NULL) {
+               struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+
+               while (!IMB_moviecacheIter_done(iter)) {
+                       ImBuf *current_ibuf = IMB_moviecacheIter_getImBuf(iter);
+                       if (STREQ(current_ibuf->name, name)) {
+                               ibuf = current_ibuf;
+                               IMB_refImBuf(ibuf);
+                               break;
+                       }
+                       IMB_moviecacheIter_step(iter);
+               }
+               IMB_moviecacheIter_free(iter);
+       }
+       BLI_spin_unlock(&image_spin);
+
+       return ibuf;
+}
+
+/* References the result, BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling BKE_image_release_ibuf().
+ *
+ * TODO(sergey): This is actually "get first entry from the cache", which is
+ *               not so much predictable. But using first loaded image buffer
+ *               was also malicious logic and all the areas which uses this
+ *               function are to be re-considered.
+ */
+ImBuf *BKE_image_get_first_ibuf(Image *image)
+{
+       ImBuf *ibuf = NULL;
+
+       BLI_spin_lock(&image_spin);
+       if (image->cache != NULL) {
+               struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+
+               while (!IMB_moviecacheIter_done(iter)) {
+                       ibuf = IMB_moviecacheIter_getImBuf(iter);
+                       IMB_refImBuf(ibuf);
+                       break;
+               }
+               IMB_moviecacheIter_free(iter);
+       }
+       BLI_spin_unlock(&image_spin);
+
+       return ibuf;
+}