* Add memcache limitor-support to imbufs
authorPeter Schlaile <peter@schlaile.de>
Sun, 5 Feb 2006 19:23:34 +0000 (19:23 +0000)
committerPeter Schlaile <peter@schlaile.de>
Sun, 5 Feb 2006 19:23:34 +0000 (19:23 +0000)
* Add ffmpeg-read support in anim.c and util.c
* Makes ImBufs refcountable. You can now increase an internal refcounter
  in ImBufs (using IMB_refImBuf) which is decreased by freeImBuf.
  This makes it possible to simply pass ImBuf pointers around in the
  sequencer saving a few memcopies.

source/blender/imbuf/IMB_imbuf.h
source/blender/imbuf/IMB_imbuf_types.h
source/blender/imbuf/SConscript
source/blender/imbuf/intern/IMB_anim.h
source/blender/imbuf/intern/Makefile
source/blender/imbuf/intern/allocimbuf.c
source/blender/imbuf/intern/anim.c
source/blender/imbuf/intern/cmap.c
source/blender/imbuf/intern/util.c

index ae7a7f527f1fa9f9f0d7e51e7aa84871950ffbd6..e78ee5901e904e01c7ee3325e009fa4f547a849d 100644 (file)
@@ -174,6 +174,28 @@ struct ImBuf *IMB_allocImBuf(short x, short y,
                                                 unsigned char d, unsigned int flags,
                                                 unsigned char bitmap);
 
+/**
+ *
+ * Increase reference count to imbuf
+ * (to delete an imbuf you have to call freeImBuf as many times as it
+ * is referenced)
+ *
+ * @attention Defined in allocimbuf.c
+ */
+
+void IMB_refImBuf(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+void IMB_cache_limiter_insert(struct ImBuf * i);
+void IMB_cache_limiter_unmanage(struct ImBuf * i);
+void IMB_cache_limiter_touch(struct ImBuf * i);
+void IMB_cache_limiter_ref(struct ImBuf * i);
+void IMB_cache_limiter_unref(struct ImBuf * i);
+int IMB_cache_limiter_get_refcount(struct ImBuf * i);
+
 /**
  *
  * @attention Defined in allocimbuf.c
index ef1aa631fc672e897aa59487122be1713bef6320..fe82b852eaac6f19b3a1b1e1c349d3ebbc274e6a 100644 (file)
@@ -94,7 +94,11 @@ typedef struct ImBuf{
        unsigned char *encodedbuffer;     /**< Compressed image only used with png currently */
        unsigned int   encodedsize;       /**< Size of data written to encodedbuffer */
        unsigned int   encodedbuffersize; /**< Size of encodedbuffer */
+
        float *rect_float;              /**< floating point Rect equivilant */
+
+       struct MEM_CacheLimiterHandle_s * c_handle; /**< handle for cache limiter */
+       int refcounter;                /**< Refcounter for multiple users */
 } ImBuf;
 
 /* Moved from BKE_bmfont_types.h because it is a userflag bit mask. */
@@ -133,8 +137,8 @@ typedef enum {
 #define IB_zbuf                        (1 << 13)
 
 #define IB_mem                 (1 << 14)
-#define IB_rectfloat   (1 << 15)
-#define IB_zbuffloat   (1 << 16)
+#define IB_rectfloat           (1 << 15)
+#define IB_zbuffloat           (1 << 16)
 
 /*
  * The bit flag is stored in the ImBuf.ftype variable.
index 938e306e7f6f8c33b170af9074930926a85ed283..ff6cad0deb17c89f600cc98d79425a86e4ef1cd6 100644 (file)
@@ -3,7 +3,7 @@ Import ('env')
 
 sources = env.Glob('intern/*.c')
 
-incs = '. ../makesdna #/intern/guardedalloc ../blenlib'
+incs = '. ../makesdna #/intern/guardedalloc #/intern/memutil ../blenlib'
 incs += ' ../avi ../quicktime ../blenkernel'
 
 incs += ' ' + env['BF_JPEG_INC']
@@ -16,6 +16,9 @@ defs = []
 if env['WITH_BF_OPENEXR'] == 1:
     defs.append('WITH_OPENEXR')
 
+if env['WITH_BF_FFMPEG'] == 1:
+    defs += ' WITH_FFMPEG'
+
 if env['WITH_BF_QUICKTIME']==1:
        incs += ' ' + env['BF_QUICKTIME_INC']
        defs.append('WITH_QUICKTIME')
index 77958f82e42b0d8e8dc498a6a481bc355256f9d4..5d597aa54632a7c302c630a9bddb036fa21e806c 100644 (file)
 #endif /* _WIN32 || __APPLE__ */
 #endif /* WITH_QUICKTIME */
 
+#ifdef WITH_FFMPEG
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+#endif
+
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
 #define ANIM_MDEC              (1 << 5)
 #define ANIM_AVI               (1 << 6)
 #define ANIM_QTIME             (1 << 7)
+#define ANIM_FFMPEG             (1 << 8)
 
 #define ANIM5_MMAP             0
 #define ANIM5_MALLOC           1
@@ -168,6 +174,16 @@ struct anim {
                /* quicktime */
        struct _QuicktimeMovie *qtime;
 #endif /* WITH_QUICKTIME */
+
+#ifdef WITH_FFMPEG
+       AVFormatContext *pFormatCtx;
+       AVCodecContext *pCodecCtx;
+       AVCodec *pCodec;
+       AVFrame *pFrameRGB;
+       AVFrame *pFrame; 
+       int videoStream;
+#endif
+
 };
 
 #endif
index 6f8fc7d31bbfb0a1f5fd2ee690427ed46a2a66b8..4efba0cd988f5cfaeb2c2db335a4f6db9f7af43b 100644 (file)
@@ -62,6 +62,7 @@ CPPFLAGS += -I../../avi
 CPPFLAGS += -I../../quicktime
 # path to the guarded memory allocator
 CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
 # This is not really needed, but until /include is cleaned, it must be
 # there for proper compilation.
 # - No, it is also needed in antialias, for listbase (nzc)
@@ -73,3 +74,7 @@ ifeq ($(WITH_QUICKTIME), true)
    CPPFLAGS += -DWITH_QUICKTIME
 endif
 
+ifeq ($(WITH_FFMPEG), true)
+   CPPFLAGS += -DWITH_FFMPEG
+endif
+
index 0c1d182f4b216fda07313db60610d40c6e45dbba..89873b92f3d912fb0051f106e34f4a3ec535acb0 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "IMB_divers.h"
 #include "IMB_allocimbuf.h"
+#include "MEM_CacheLimiterC-Api.h"
 
 static unsigned int dfltcmap[16] = {
        0x00000000, 0xffffffff, 0x777777ff, 0xccccccff, 
@@ -135,17 +136,27 @@ void IMB_freecmapImBuf(struct ImBuf * ibuf)
 void IMB_freeImBuf(struct ImBuf * ibuf)
 {
        if (ibuf){
-               imb_freeplanesImBuf(ibuf);
-               imb_freerectImBuf(ibuf);
-               imb_freerectfloatImBuf(ibuf);
-               IMB_freezbufImBuf(ibuf);
-               IMB_freezbuffloatImBuf(ibuf);
-               IMB_freecmapImBuf(ibuf);
-               freeencodedbufferImBuf(ibuf);
-               MEM_freeN(ibuf);
+               if (ibuf->refcounter > 0) {
+                       ibuf->refcounter--;
+               } else {
+                       imb_freeplanesImBuf(ibuf);
+                       imb_freerectImBuf(ibuf);
+                       imb_freerectfloatImBuf(ibuf);
+                       IMB_freezbufImBuf(ibuf);
+                       IMB_freezbuffloatImBuf(ibuf);
+                       IMB_freecmapImBuf(ibuf);
+                       freeencodedbufferImBuf(ibuf);
+                       IMB_cache_limiter_unmanage(ibuf);
+                       MEM_freeN(ibuf);
+               }
        }
 }
 
+void IMB_refImBuf(struct ImBuf * ibuf)
+{
+       ibuf->refcounter++;
+}
+
 short addzbufImBuf(struct ImBuf * ibuf)
 {
        int size;
@@ -444,7 +455,8 @@ struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1)
        
        // set malloc flag
        tbuf.mall               = ibuf2->mall;
-       
+       tbuf.c_handle           = 0;
+
        *ibuf2 = tbuf;
        
        if (ibuf1->cmap){
@@ -454,3 +466,81 @@ struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1)
 
        return(ibuf2);
 }
+
+/* support for cache limiting */
+
+static void imbuf_cache_destructor(void * data)
+{
+       struct ImBuf * ibuf = (struct ImBuf*) data;
+
+       imb_freeplanesImBuf(ibuf);
+       imb_freerectImBuf(ibuf);
+       IMB_freezbufImBuf(ibuf);
+       IMB_freecmapImBuf(ibuf);
+       freeencodedbufferImBuf(ibuf);
+       
+       ibuf->c_handle = 0;
+}
+
+static MEM_CacheLimiterC ** get_imbuf_cache_limiter()
+{
+       static MEM_CacheLimiterC * c = 0;
+       if (!c) {
+               c = new_MEM_CacheLimiter(imbuf_cache_destructor);
+       }
+       return &c;
+}
+
+void IMB_free_cache_limiter()
+{
+       delete_MEM_CacheLimiter(*get_imbuf_cache_limiter());
+       *get_imbuf_cache_limiter() = 0;
+}
+
+void IMB_cache_limiter_insert(struct ImBuf * i)
+{
+       if (!i->c_handle) {
+               i->c_handle = MEM_CacheLimiter_insert(
+                       *get_imbuf_cache_limiter(), i);
+               MEM_CacheLimiter_ref(i->c_handle);
+               MEM_CacheLimiter_enforce_limits(
+                       *get_imbuf_cache_limiter());
+               MEM_CacheLimiter_unref(i->c_handle);
+       }
+}
+
+void IMB_cache_limiter_unmanage(struct ImBuf * i)
+{
+       if (i->c_handle) {
+               MEM_CacheLimiter_unmanage(i->c_handle);
+               i->c_handle = 0;
+       }
+}
+
+void IMB_cache_limiter_touch(struct ImBuf * i)
+{
+       if (i->c_handle) {
+               MEM_CacheLimiter_touch(i->c_handle);
+       }
+}
+
+void IMB_cache_limiter_ref(struct ImBuf * i)
+{
+       if (i->c_handle) {
+               MEM_CacheLimiter_ref(i->c_handle);
+       }
+}
+
+void IMB_cache_limiter_unref(struct ImBuf * i)
+{
+       if (i->c_handle) {
+               MEM_CacheLimiter_unref(i->c_handle);
+       }
+}
+
+int IMB_cache_limiter_get_refcount(struct ImBuf * i)
+{
+       if (i->c_handle) {
+               MEM_CacheLimiter_get_refcount(i->c_handle);
+       }
+}
index 51fadc5c06accb490fb2680be23de868f231fb6a..ad563cc3bb2ff712b1122aded3feeeb488655f50 100644 (file)
 #include "IMB_anim.h"
 #include "IMB_anim5.h"
 
+#ifdef WITH_FFMPEG
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+
+#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+#define FFMPEG_OLD_FRAME_RATE 1
+#else
+#define FFMPEG_CODEC_IS_POINTER 1
+#endif
+
+#endif
 
 /****/
 
@@ -293,6 +304,7 @@ void IMB_free_anim_ibuf(struct anim * anim) {
        anim->ibuf1 = anim->ibuf2 = NULL;
 }
 
+static void free_anim_ffmpeg(struct anim * anim);
 
 void IMB_free_anim(struct anim * anim) {
        if (anim == NULL) {
@@ -308,6 +320,9 @@ void IMB_free_anim(struct anim * anim) {
 #ifdef WITH_QUICKTIME
        free_anim_quicktime(anim);
 #endif
+#ifdef WITH_FFMPEG
+       free_anim_ffmpeg(anim);
+#endif
 
        free(anim);
 }
@@ -473,6 +488,287 @@ static ImBuf * avi_fetchibuf (struct anim *anim, int position) {
        return ibuf;
 }
 
+#ifdef WITH_FFMPEG
+
+extern void do_init_ffmpeg();
+
+static int startffmpeg(struct anim * anim) {
+       int            i, videoStream;
+
+       AVCodec *pCodec;
+       AVFormatContext *pFormatCtx;
+       AVCodecContext *pCodecCtx;
+
+       if (anim == 0) return(-1);
+
+       do_init_ffmpeg();
+
+       if(av_open_input_file(&pFormatCtx, anim->name, NULL, 0, NULL)!=0) {
+               return -1;
+       }
+
+       if(av_find_stream_info(pFormatCtx)<0) {
+               av_close_input_file(pFormatCtx);
+               return -1;
+       }
+
+       dump_format(pFormatCtx, 0, anim->name, 0);
+
+
+        /* Find the first video stream */
+       videoStream=-1;
+       for(i=0; i<pFormatCtx->nb_streams; i++)
+#ifdef FFMPEG_CODEC_IS_POINTER
+               if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
+#else
+               if(pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO)
+#endif
+               {
+                       videoStream=i;
+                       break;
+               }
+
+       if(videoStream==-1) {
+               av_close_input_file(pFormatCtx);
+               return -1;
+       }
+
+#ifdef FFMPEG_CODEC_IS_POINTER
+       pCodecCtx=pFormatCtx->streams[videoStream]->codec;
+#else
+       pCodecCtx=&pFormatCtx->streams[videoStream]->codec;
+#endif
+
+        /* Find the decoder for the video stream */
+       pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
+       if(pCodec==NULL) {
+               avcodec_close(pCodecCtx);
+               av_close_input_file(pFormatCtx);
+               return -1;
+       }
+
+       pCodecCtx->workaround_bugs = 1;
+       pCodecCtx->lowres = 0;
+       pCodecCtx->idct_algo= FF_IDCT_AUTO;
+       pCodecCtx->skip_frame= AVDISCARD_DEFAULT;
+       pCodecCtx->skip_idct= AVDISCARD_DEFAULT;
+       pCodecCtx->skip_loop_filter= AVDISCARD_DEFAULT;
+       pCodecCtx->error_resilience= FF_ER_CAREFUL;
+       pCodecCtx->error_concealment= 3;
+
+       if(avcodec_open(pCodecCtx, pCodec)<0) {
+               avcodec_close(pCodecCtx);
+               av_close_input_file(pFormatCtx);
+               return -1;
+       }
+
+#ifdef FFMPEG_OLD_FRAME_RATE
+       if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1)
+               pCodecCtx->frame_rate_base=1000;
+
+
+       anim->duration = pFormatCtx->duration * pCodecCtx->frame_rate 
+               / pCodecCtx->frame_rate_base / AV_TIME_BASE;
+#else
+       anim->duration = pFormatCtx->duration * av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate) / AV_TIME_BASE;
+
+#endif
+       anim->params = 0;
+
+       anim->x = pCodecCtx->width;
+       anim->y = pCodecCtx->height;
+       anim->interlacing = 0;
+       anim->orientation = 0;
+       anim->framesize = anim->x * anim->y * 4;
+
+       anim->curposition = -1;
+
+       anim->pFormatCtx = pFormatCtx;
+       anim->pCodecCtx = pCodecCtx;
+       anim->pCodec = pCodec;
+       anim->videoStream = videoStream;
+
+       anim->pFrame = avcodec_alloc_frame();
+       anim->pFrameRGB = avcodec_alloc_frame();
+
+       if (avpicture_get_size(PIX_FMT_RGBA32, anim->x, anim->y)
+           != anim->x * anim->y * 4) {
+               fprintf (stderr,
+                        "ffmpeg has changed alloc scheme ... ARGHHH!\n");
+               avcodec_close(anim->pCodecCtx);
+               av_close_input_file(anim->pFormatCtx);
+               av_free(anim->pFrameRGB);
+               av_free(anim->pFrame);
+               return -1;
+       }
+
+       /*printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/
+       return (0);
+}
+
+static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
+       ImBuf * ibuf;
+       int frameFinished;
+       AVPacket packet;
+       offset_t pos_to_match = AV_NOPTS_VALUE;
+       int pos_found = 1;
+
+       if (anim == 0) return (0);
+
+       ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect, 0);
+
+       avpicture_fill((AVPicture *)anim->pFrameRGB, 
+                      (unsigned char*) ibuf->rect, 
+                      PIX_FMT_RGBA32, anim->x, anim->y);
+
+       if (position != anim->curposition + 1) { 
+               int keyframe_found = 0;
+               int scan_pos = position;
+               int max_scan = 18; /* max mpeg 1/2 gop size */
+#ifdef FFMPEG_OLD_FRAME_RATE
+               long long pos = (long long) anim->pCodecCtx->frame_rate_base 
+                       * position * AV_TIME_BASE 
+                       / anim->pCodecCtx->frame_rate;
+#else
+               long long pos = (long long) position * AV_TIME_BASE 
+                  / av_q2d(anim->pFormatCtx->streams[anim->videoStream]
+                           ->r_frame_rate);
+#endif
+               long long st_time = anim->pFormatCtx
+                       ->streams[anim->videoStream]->start_time;
+               if (st_time != AV_NOPTS_VALUE) {
+                       pos += st_time;
+               }
+
+               av_seek_frame(anim->pFormatCtx, -1, 
+                             pos, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD );
+
+               while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
+                       if(packet.stream_index == anim->videoStream) {
+                               pos_to_match 
+                                       = url_ftell(&anim->pFormatCtx->pb);
+                               if ((packet.flags & PKT_FLAG_KEY) != 0) {
+                                       keyframe_found = 1;
+                               }
+                               av_free_packet(&packet);
+                               break;
+                       }
+                       av_free_packet(&packet);
+               }
+               /* if all ffmpeg seek bugs are fixed, the following
+                  loop is obsolete ... (but does not hurt very much...)
+               */
+
+               while (!keyframe_found && max_scan--) {
+                       scan_pos--;
+#ifdef FFMPEG_OLD_FRAME_RATE
+                       pos = (long long) 
+                               anim->pCodecCtx->frame_rate_base 
+                               * scan_pos * AV_TIME_BASE 
+                               / anim->pCodecCtx->frame_rate;
+#else
+                       pos = (long long) scan_pos * AV_TIME_BASE 
+                               / av_q2d(anim->pFormatCtx
+                                        ->streams[anim->videoStream]
+                                        ->r_frame_rate);
+#endif
+                       av_seek_frame(anim->pFormatCtx, -1, 
+                                     pos, 
+                                     AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
+
+                       while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
+                               if(packet.stream_index == anim->videoStream) {
+                                       if ((packet.flags & PKT_FLAG_KEY) 
+                                           != 0) {
+                                               keyframe_found = 1;
+                                       } 
+                                       av_free_packet(&packet);
+                                       break;
+                               }
+                               av_free_packet(&packet);
+                       }
+               }
+
+               if (max_scan <= 0) {
+                       fprintf(stderr, 
+                               "Warning: Key frame not found, "
+                               "doesn't hurt, but _slow_...!\n");
+               }
+
+               av_seek_frame(anim->pFormatCtx, -1, 
+                             pos, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
+
+               pos_found = 0;
+               avcodec_flush_buffers(anim->pCodecCtx);
+       }
+
+       while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
+               if (packet.stream_index == anim->videoStream 
+                   && !pos_found) {
+                       if (url_ftell(&anim->pFormatCtx->pb) == pos_to_match) {
+                               pos_found = 1;
+                       } 
+               }
+               if(packet.stream_index == anim->videoStream) {
+                       avcodec_decode_video(anim->pCodecCtx, 
+                                            anim->pFrame, &frameFinished, 
+                                            packet.data, packet.size);
+
+                       if(frameFinished && pos_found) {
+                               unsigned char * p =(unsigned char*) ibuf->rect;
+                               unsigned char * e = p + anim->x * anim->y * 4;
+
+                               img_convert((AVPicture *)anim->pFrameRGB, 
+                                           PIX_FMT_RGBA32, 
+                                           (AVPicture*)anim->pFrame, 
+                                           anim->pCodecCtx->pix_fmt, 
+                                           anim->pCodecCtx->width, 
+                                           anim->pCodecCtx->height);
+                               IMB_flipy(ibuf);
+                               if (G.order == L_ENDIAN) {
+                                       /* BGRA -> RGBA */
+                                       while (p != e) {
+                                               unsigned char a = p[0];
+                                               p[0] = p[2];
+                                               p[2] = a;
+                                               p += 4;
+                                       }
+                               } else {
+                                       /* ARGB -> RGBA */
+                                       while (p != e) {
+                                               unsigned long a =
+                                                       *(unsigned long*) p;
+                                               a = (a << 8) | p[0];
+                                               *(unsigned long*) p = a;
+                                               p += 4;
+                                       }
+                               }
+                               av_free_packet(&packet);
+                               break;
+                       }
+               }
+
+               av_free_packet(&packet);
+       }
+
+       return(ibuf);
+}
+
+static void free_anim_ffmpeg(struct anim * anim) {
+       if (anim == NULL) return;
+
+       if (anim->pCodecCtx) {
+               avcodec_close(anim->pCodecCtx);
+               av_close_input_file(anim->pFormatCtx);
+               av_free(anim->pFrameRGB);
+               av_free(anim->pFrame);
+       }
+       anim->duration = 0;
+}
+
+#endif
+
+
 /* probeer volgende plaatje te lezen */
 /* Geen plaatje, probeer dan volgende animatie te openen */
 /* gelukt, haal dan eerste plaatje van animatie */
@@ -488,6 +784,9 @@ static struct ImBuf * anim_getnew(struct anim * anim) {
 #ifdef WITH_QUICKTIME
        free_anim_quicktime(anim);
 #endif
+#ifdef WITH_FFMPEG
+       free_anim_ffmpeg(anim);
+#endif
 
        if (anim->curtype != 0) return (0);
        anim->curtype = imb_get_anim_type(anim->name);  
@@ -520,6 +819,12 @@ static struct ImBuf * anim_getnew(struct anim * anim) {
                if (startquicktime(anim)) return (0);
                ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0);
                break;
+#endif
+#ifdef WITH_FFMPEG
+       case ANIM_FFMPEG:
+               if (startffmpeg(anim)) return (0);
+               ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0);
+               break;
 #endif
        }
 
@@ -584,6 +889,12 @@ struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
                ibuf = qtime_fetchibuf(anim, position);
                if (ibuf) anim->curposition = position;
                break;
+#endif
+#ifdef WITH_FFMPEG
+       case ANIM_FFMPEG:
+               ibuf = ffmpeg_fetchibuf(anim, position);
+               if (ibuf) anim->curposition = position;
+               break;
 #endif
        }
 
index c955fbf7e60a028159f80ce162217d8d6b4c7ad4..7b4962d8837aa8bfb41d053c8d992123c828f93c 100644 (file)
@@ -49,6 +49,7 @@ static short lastmincol;
 static short lastcbits;
 short alpha_col0 = FALSE;
 
+extern void IMB_free_cache_limiter();
 
 /*
  * there still is a bug here. If you want to convert an image to a 1 bit colormap you get
@@ -61,6 +62,7 @@ void IMB_freeImBufdata(void)
        lastcube= 0;
        if (lastcoltab) free(lastcoltab);
        lastcoltab= 0;
+       IMB_free_cache_limiter();
 }
 
 
index 8110a115471ba8c07bc22225cb58a37202521094..fdb1bed387027869860e7ad3dc132b5fe3e37881 100644 (file)
 #include "quicktime_import.h"
 #endif
 
+#ifdef WITH_FFMPEG
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/avformat.h>
+
+#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+#define FFMPEG_OLD_FRAME_RATE 1
+#else
+#define FFMPEG_CODEC_IS_POINTER 1
+#endif
+
+#endif
+
 #define UTIL_DEBUG 0
 
 /* from misc_util: flip the bytes from x  */
@@ -195,15 +207,103 @@ static int isqtime (char *name) {
 }
 #endif
 
+#ifdef WITH_FFMPEG
+void do_init_ffmpeg()
+{
+       static int ffmpeg_init = 0;
+       if (!ffmpeg_init) {
+               ffmpeg_init = 1;
+               av_register_all();
+       }
+}
+
+
+static int isffmpeg (char *filename) {
+       AVFormatContext *pFormatCtx;
+       int            i, videoStream;
+       AVCodec *pCodec;
+       AVCodecContext *pCodecCtx;
+
+       do_init_ffmpeg();
+
+       if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0) {
+               fprintf(stderr, "isffmpeg: av_open_input_file failed\n");
+               return 0;
+       }
+
+       if(av_find_stream_info(pFormatCtx)<0) {
+               fprintf(stderr, "isffmpeg: av_find_stream_info failed\n");
+               av_close_input_file(pFormatCtx);
+               return 0;
+       }
+
+       dump_format(pFormatCtx, 0, filename, 0);
+
+
+        /* Find the first video stream */
+       videoStream=-1;
+       for(i=0; i<pFormatCtx->nb_streams; i++)
+#ifdef FFMPEG_CODEC_IS_POINTER
+               if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
+#else
+               if(pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO)
+#endif
+               {
+                       videoStream=i;
+                       break;
+               }
+
+#ifdef FFMPEG_CODEC_IS_POINTER
+       pCodecCtx=pFormatCtx->streams[videoStream]->codec;
+#else
+       pCodecCtx=&pFormatCtx->streams[videoStream]->codec;
+#endif
+
+       if(videoStream==-1) {
+               avcodec_close(pCodecCtx);
+               av_close_input_file(pFormatCtx);
+               return 0;
+       }
+
+
+        /* Find the decoder for the video stream */
+       pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
+       if(pCodec==NULL) {
+               avcodec_close(pCodecCtx);
+               av_close_input_file(pFormatCtx);
+               return 0;
+       }
+
+       if(pCodec->capabilities & CODEC_CAP_TRUNCATED)
+               pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
+
+       if(avcodec_open(pCodecCtx, pCodec)<0) {
+               avcodec_close(pCodecCtx);
+               av_close_input_file(pFormatCtx);
+               return 0;
+       }
+
+       avcodec_close(pCodecCtx);
+       av_close_input_file(pFormatCtx);
+
+       return 1;
+}
+#endif
+
 int imb_get_anim_type(char * name) {
        int type;
        struct stat st;
 
        if(UTIL_DEBUG) printf("in getanimtype: %s\n", name);
 
+#ifdef WITH_FFMPEG
+       /* stat test below fails on large files > 4GB */
+       if (isffmpeg(name)) return (ANIM_FFMPEG);
+#endif
+
        if (ib_stat(name,&st) == -1) return(0);
        if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
-       
+
        if (isavi(name)) return (ANIM_AVI);
 
        if (ismovie(name)) return (ANIM_MOVIE);
@@ -223,6 +323,7 @@ int IMB_isanim(char *filename) {
                if (G.have_quicktime){
                        if(             BLI_testextensie(filename, ".avi")
                                ||      BLI_testextensie(filename, ".flc")
+                               ||      BLI_testextensie(filename, ".dv")
                                ||      BLI_testextensie(filename, ".mov")
                                ||      BLI_testextensie(filename, ".movie")
                                ||      BLI_testextensie(filename, ".mv")) {
@@ -232,6 +333,7 @@ int IMB_isanim(char *filename) {
                        }
                } else { // no quicktime
                        if(             BLI_testextensie(filename, ".avi")
+                               ||      BLI_testextensie(filename, ".dv")
                                ||      BLI_testextensie(filename, ".mv")) {
                                type = imb_get_anim_type(filename);
                        }