Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Mueller <nexyon@gmail.com>2011-08-30 12:22:03 +0400
committerJoerg Mueller <nexyon@gmail.com>2011-08-30 12:22:03 +0400
commit43ab8e86247b7889d16d915b4f370ceb618aaad4 (patch)
tree64b1fec1adcc399eb1de5cd86ebafd753a921d8d /source/blender/imbuf
parent5b5e600db6f529ad7e1af9d4bb3a193be2265342 (diff)
parentd049a722fea3d150fbfad06ffdbbb5c150717134 (diff)
* Merge trunk up to r39790.soc-2011-pepper
* Subversion bump (also for init_userdef_do_versions). * Minor fix for compilation without ffmpeg.
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r--source/blender/imbuf/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/IMB_imbuf.h69
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h24
-rw-r--r--source/blender/imbuf/intern/IMB_indexer.h133
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c13
-rw-r--r--source/blender/imbuf/intern/anim_movie.c566
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp16
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c1142
-rw-r--r--source/blender/imbuf/intern/indexer_dv.c391
-rw-r--r--source/blender/imbuf/intern/thumbs.c4
-rw-r--r--source/blender/imbuf/intern/tiff.c2
-rw-r--r--source/blender/imbuf/intern/util.c7
13 files changed, 2206 insertions, 164 deletions
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index 18b5eff5c73..ff13be20d4e 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -73,6 +73,7 @@ set(SRC
intern/tiff.c
intern/util.c
intern/writeimage.c
+ intern/indexer.c
IMB_imbuf.h
IMB_imbuf_types.h
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 36123592c54..1fbe8e01fd4 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -133,6 +133,7 @@ struct ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y,
*/
void IMB_refImBuf(struct ImBuf *ibuf);
+struct ImBuf * IMB_makeSingleUser(struct ImBuf *ibuf);
/**
*
@@ -193,17 +194,70 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode);
/**
+ *
+ * @attention Defined in indexer.c
+ */
+
+typedef enum IMB_Timecode_Type {
+ IMB_TC_NONE = 0, /* don't use timecode files at all */
+ IMB_TC_RECORD_RUN = 1, /* use images in the order as they are recorded
+ (currently, this is the only one implemented
+ and is a sane default)
+ */
+ IMB_TC_FREE_RUN = 2, /* use global timestamp written by recording
+ device (prosumer camcorders e.g. can do
+ that) */
+ IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN = 4,
+ /* interpolate a global timestamp using the
+ record date and time written by recording
+ device (*every* consumer camcorder can do
+ that :) )*/
+ IMB_TC_MAX_SLOT = 3
+} IMB_Timecode_Type;
+
+typedef enum IMB_Proxy_Size {
+ IMB_PROXY_NONE = 0,
+ IMB_PROXY_25 = 1,
+ IMB_PROXY_50 = 2,
+ IMB_PROXY_75 = 4,
+ IMB_PROXY_100 = 8,
+ IMB_PROXY_MAX_SLOT = 4
+} IMB_Proxy_Size;
+
+/* defaults to BL_proxy within the directory of the animation */
+void IMB_anim_set_index_dir(struct anim * anim, const char * dir);
+
+int IMB_anim_index_get_frame_index(struct anim * anim, IMB_Timecode_Type tc,
+ int position);
+
+/* will rebuild all used indices and proxies at once */
+void IMB_anim_index_rebuild(struct anim * anim,
+ IMB_Timecode_Type build_tcs,
+ IMB_Proxy_Size build_preview_sizes,
+ int build_quality,
+ short *stop, short *do_update, float *progress);
+
+/**
* Return the length (in frames) of the given @a anim.
*/
-int IMB_anim_get_duration(struct anim *anim);
+int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc);
+
+
+/**
+ * Return the fps contained in movie files (function rval is FALSE,
+ * and frs_sec and frs_sec_base untouched if none available!)
+ */
+int IMB_anim_get_fps(struct anim * anim,
+ short * frs_sec, float * frs_sec_base);
/**
*
* @attention Defined in anim.c
*/
-struct anim *IMB_open_anim(const char *name, int ib_flags);
+struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex);
void IMB_close_anim(struct anim *anim);
+
/**
*
* @attention Defined in anim.c
@@ -218,7 +272,10 @@ int IMB_anim_get_preseek(struct anim *anim);
* @attention Defined in anim.c
*/
-struct ImBuf *IMB_anim_absolute(struct anim *anim, int position);
+struct ImBuf *IMB_anim_absolute(
+ struct anim *anim, int position,
+ IMB_Timecode_Type tc /* = 1 = IMB_TC_RECORD_RUN */,
+ IMB_Proxy_Size preview_size /* = 0 = IMB_PROXY_NONE */);
/**
*
@@ -231,12 +288,6 @@ struct ImBuf *IMB_anim_previewframe(struct anim *anim);
*
* @attention Defined in anim.c
*/
-void IMB_free_anim_ibuf(struct anim *anim);
-
-/**
- *
- * @attention Defined in anim.c
- */
void IMB_free_anim(struct anim *anim);
/**
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index fba0772dd93..8436846bf2e 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -127,19 +127,22 @@
#define MAXNUMSTREAMS 50
struct _AviMovie;
+struct anim_index;
struct anim {
int ib_flags;
int curtype;
int curposition; /* index 0 = 1e, 1 = 2e, enz. */
int duration;
+ short frs_sec;
+ float frs_sec_base;
int x, y;
/* voor op nummer */
char name[256];
/* voor sequence */
char first[256];
-
+
/* movie */
void *movie;
void *track;
@@ -148,9 +151,7 @@ struct anim {
size_t framesize;
int interlacing;
int preseek;
-
- /* data */
- struct ImBuf * ibuf1, * ibuf2;
+ int streamindex;
/* avi */
struct _AviMovie *avi;
@@ -179,11 +180,26 @@ struct anim {
AVFrame *pFrameDeinterlaced;
struct SwsContext *img_convert_ctx;
int videoStream;
+
+ struct ImBuf * last_frame;
+ int64_t last_pts;
+ int64_t next_pts;
+ int64_t next_undecoded_pts;
+ AVPacket next_packet;
#endif
#ifdef WITH_REDCODE
struct redcode_handle * redcodeCtx;
#endif
+
+ char index_dir[256];
+
+ int proxies_tried;
+ int indices_tried;
+
+ struct anim * proxy_anim[IMB_PROXY_MAX_SLOT];
+ struct anim_index * curr_idx[IMB_TC_MAX_SLOT];
+
};
#endif
diff --git a/source/blender/imbuf/intern/IMB_indexer.h b/source/blender/imbuf/intern/IMB_indexer.h
new file mode 100644
index 00000000000..f55420fd106
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_indexer.h
@@ -0,0 +1,133 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * Contributor(s): Peter Schlaile
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#ifndef IMB_INDEXER_H
+#define IMB_INDEXER_H
+
+#ifdef WIN32
+#include <io.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "BKE_utildefines.h"
+#include "IMB_anim.h"
+
+/*
+ seperate animation index files to solve the following problems:
+
+ a) different timecodes within one file (like DTS/PTS, Timecode-Track,
+ "implicit" timecodes within DV-files and HDV-files etc.)
+ b) seeking difficulties within ffmpeg for files with timestamp holes
+ c) broken files that miss several frames / have varying framerates
+ d) use proxies accordingly
+
+ ... we need index files, that provide us with
+
+ the binary(!) position, where we have to seek into the file *and*
+ the continuous frame number (ignoring the holes) starting from the
+ beginning of the file, so that we know, which proxy frame to serve.
+
+ This index has to be only built once for a file and is written into
+ the BL_proxy directory structure for later reuse in different blender files.
+
+*/
+
+typedef struct anim_index_entry {
+ int frameno;
+ unsigned long long seek_pos;
+ unsigned long long seek_pos_dts;
+ unsigned long long pts;
+} anim_index_entry;
+
+struct anim_index {
+ char name[256];
+
+ int num_entries;
+ struct anim_index_entry * entries;
+};
+
+struct anim_index_builder;
+
+typedef struct anim_index_builder {
+ FILE * fp;
+ char name[FILE_MAXDIR + FILE_MAXFILE];
+ char temp_name[FILE_MAXDIR + FILE_MAXFILE];
+
+ void * private_data;
+
+ void (*delete_priv_data)(struct anim_index_builder * idx);
+ void (*proc_frame)(struct anim_index_builder * idx,
+ unsigned char * buffer,
+ int data_size,
+ struct anim_index_entry * entry);
+} anim_index_builder;
+
+anim_index_builder * IMB_index_builder_create(const char * name);
+void IMB_index_builder_add_entry(anim_index_builder * fp,
+ int frameno, unsigned long long seek_pos,
+ unsigned long long seek_pos_dts,
+ unsigned long long pts);
+
+void IMB_index_builder_proc_frame(anim_index_builder * fp,
+ unsigned char * buffer,
+ int data_size,
+ int frameno, unsigned long long seek_pos,
+ unsigned long long seek_pos_dts,
+ unsigned long long pts);
+
+void IMB_index_builder_finish(anim_index_builder * fp, int rollback);
+
+struct anim_index * IMB_indexer_open(const char * name);
+unsigned long long IMB_indexer_get_seek_pos(
+ struct anim_index * idx, int frameno_index);
+unsigned long long IMB_indexer_get_seek_pos_dts(
+ struct anim_index * idx, int frameno_index);
+
+int IMB_indexer_get_frame_index(struct anim_index * idx, int frameno);
+unsigned long long IMB_indexer_get_pts(struct anim_index * idx,
+ int frame_index);
+int IMB_indexer_get_duration(struct anim_index * idx);
+
+int IMB_indexer_can_scan(struct anim_index * idx,
+ int old_frame_index, int new_frame_index);
+
+void IMB_indexer_close(struct anim_index * idx);
+
+void IMB_free_indices(struct anim * anim);
+
+int IMB_anim_index_get_frame_index(
+ struct anim * anim, IMB_Timecode_Type tc, int position);
+
+struct anim * IMB_anim_open_proxy(
+ struct anim * anim, IMB_Proxy_Size preview_size);
+struct anim_index * IMB_anim_open_index(
+ struct anim * anim, IMB_Timecode_Type tc);
+
+int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size);
+int IMB_timecode_to_array_index(IMB_Timecode_Type tc);
+
+#endif
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 59772771f3b..6ce6c9409d1 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -177,6 +177,19 @@ void IMB_refImBuf(ImBuf *ibuf)
ibuf->refcounter++;
}
+ImBuf * IMB_makeSingleUser(ImBuf *ibuf)
+{
+ ImBuf * rval;
+
+ if (!ibuf || ibuf->refcounter == 0) { return ibuf; }
+
+ rval = IMB_dupImBuf(ibuf);
+
+ IMB_freeImBuf(ibuf);
+
+ return rval;
+}
+
short addzbufImBuf(ImBuf *ibuf)
{
int size;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 8b0104fcdca..7b172008bee 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -57,6 +57,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
+#include <math.h>
#ifndef _WIN32
#include <dirent.h>
#else
@@ -66,6 +67,7 @@
#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail
BLI_countlist BLI_stringdec */
#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
#include "MEM_guardedalloc.h"
@@ -90,6 +92,7 @@
#include "IMB_allocimbuf.h"
#include "IMB_anim.h"
+#include "IMB_indexer.h"
#ifdef WITH_FFMPEG
#include <libavformat/avformat.h>
@@ -304,15 +307,6 @@ static void free_anim_avi (struct anim *anim) {
anim->duration = 0;
}
-void IMB_free_anim_ibuf(struct anim * anim) {
- if (anim == NULL) return;
-
- if (anim->ibuf1) IMB_freeImBuf(anim->ibuf1);
- if (anim->ibuf2) IMB_freeImBuf(anim->ibuf2);
-
- anim->ibuf1 = anim->ibuf2 = NULL;
-}
-
#ifdef WITH_FFMPEG
static void free_anim_ffmpeg(struct anim * anim);
#endif
@@ -326,7 +320,6 @@ void IMB_free_anim(struct anim * anim) {
return;
}
- IMB_free_anim_ibuf(anim);
free_anim_movie(anim);
free_anim_avi(anim);
@@ -339,6 +332,7 @@ void IMB_free_anim(struct anim * anim) {
#ifdef WITH_REDCODE
free_anim_redcode(anim);
#endif
+ IMB_free_indices(anim);
MEM_freeN(anim);
}
@@ -350,13 +344,14 @@ void IMB_close_anim(struct anim * anim) {
}
-struct anim * IMB_open_anim( const char * name, int ib_flags) {
+struct anim * IMB_open_anim( const char * name, int ib_flags, int streamindex) {
struct anim * anim;
anim = (struct anim*)MEM_callocN(sizeof(struct anim), "anim struct");
if (anim != NULL) {
BLI_strncpy(anim->name, name, sizeof(anim->name));
anim->ib_flags = ib_flags;
+ anim->streamindex = streamindex;
}
return(anim);
}
@@ -368,10 +363,13 @@ static int startavi (struct anim *anim) {
#if defined(_WIN32) && !defined(FREE_WINDOWS)
HRESULT hr;
int i, firstvideo = -1;
+ int streamcount;
BYTE abFormat[1024];
LONG l;
LPBITMAPINFOHEADER lpbi;
AVISTREAMINFO avis;
+
+ streamcount = anim->streamindex;
#endif
anim->avi = MEM_callocN (sizeof(AviMovie),"animavi");
@@ -396,6 +394,10 @@ static int startavi (struct anim *anim) {
AVIStreamInfo(anim->pavi[i], &avis, sizeof(avis));
if ((avis.fccType == streamtypeVIDEO) && (firstvideo == -1)) {
+ if (streamcount > 0) {
+ streamcount--;
+ continue;
+ }
anim->pgf = AVIStreamGetFrameOpen(anim->pavi[i], NULL);
if (anim->pgf) {
firstvideo = i;
@@ -496,14 +498,14 @@ static ImBuf * avi_fetchibuf (struct anim *anim, int position) {
for (y=0; y < anim->y; y++) {
memcpy (&(ibuf->rect)[((anim->y-y)-1)*anim->x], &tmp[y*anim->x],
- anim->x * 4);
+ anim->x * 4);
}
MEM_freeN (tmp);
}
-
+
ibuf->profile = IB_PROFILE_SRGB;
-
+
return ibuf;
}
@@ -517,6 +519,9 @@ static int startffmpeg(struct anim * anim) {
AVCodec *pCodec;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
+ int frs_num;
+ double frs_den;
+ int streamcount;
#ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
/* The following for color space determination */
@@ -527,6 +532,8 @@ static int startffmpeg(struct anim * anim) {
if (anim == 0) return(-1);
+ streamcount = anim->streamindex;
+
do_init_ffmpeg();
if(av_open_input_file(&pFormatCtx, anim->name, NULL, 0, NULL)!=0) {
@@ -541,12 +548,17 @@ static int startffmpeg(struct anim * anim) {
av_dump_format(pFormatCtx, 0, anim->name, 0);
- /* Find the first video stream */
- videoStream=-1;
- for(i=0; i<pFormatCtx->nb_streams; i++)
- if(pFormatCtx->streams[i]->codec->codec_type
+ /* Find the video stream */
+ videoStream = -1;
+
+ for(i = 0; i < pFormatCtx->nb_streams; i++)
+ if (pFormatCtx->streams[i]->codec->codec_type
== AVMEDIA_TYPE_VIDEO) {
- videoStream=i;
+ if (streamcount > 0) {
+ streamcount--;
+ continue;
+ }
+ videoStream = i;
break;
}
@@ -557,16 +569,16 @@ static int startffmpeg(struct anim * anim) {
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
- /* Find the decoder for the video stream */
- pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
- if(pCodec==NULL) {
+ /* Find the decoder for the video stream */
+ pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
+ if(pCodec == NULL) {
av_close_input_file(pFormatCtx);
return -1;
}
pCodecCtx->workaround_bugs = 1;
- if(avcodec_open(pCodecCtx, pCodec)<0) {
+ if(avcodec_open(pCodecCtx, pCodec) < 0) {
av_close_input_file(pFormatCtx);
return -1;
}
@@ -575,6 +587,19 @@ static int startffmpeg(struct anim * anim) {
* av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)
/ AV_TIME_BASE);
+ frs_num = pFormatCtx->streams[videoStream]->r_frame_rate.num;
+ frs_den = pFormatCtx->streams[videoStream]->r_frame_rate.den;
+
+ frs_den *= AV_TIME_BASE;
+
+ while (frs_num % 10 == 0 && frs_den >= 2.0 && frs_num > 10) {
+ frs_num /= 10;
+ frs_den /= 10;
+ }
+
+ anim->frs_sec = frs_num;
+ anim->frs_sec_base = frs_den;
+
anim->params = 0;
anim->x = pCodecCtx->width;
@@ -584,6 +609,11 @@ static int startffmpeg(struct anim * anim) {
anim->framesize = anim->x * anim->y * 4;
anim->curposition = -1;
+ anim->last_frame = 0;
+ anim->last_pts = -1;
+ anim->next_pts = -1;
+ anim->next_undecoded_pts = -1;
+ anim->next_packet.stream_index = -1;
anim->pFormatCtx = pFormatCtx;
anim->pCodecCtx = pCodecCtx;
@@ -666,10 +696,19 @@ static int startffmpeg(struct anim * anim) {
return (0);
}
-static void ffmpeg_postprocess(struct anim * anim, ImBuf * ibuf,
- int * filter_y)
+/* postprocess the image in anim->pFrame and do color conversion
+ and deinterlacing stuff.
+
+ Output is anim->last_frame
+*/
+
+static void ffmpeg_postprocess(struct anim * anim)
{
AVFrame * input = anim->pFrame;
+ ImBuf * ibuf = anim->last_frame;
+ int filter_y = 0;
+
+ ibuf->profile = IB_PROFILE_SRGB;
/* This means the data wasnt read properly,
this check stops crashing */
@@ -690,12 +729,16 @@ static void ffmpeg_postprocess(struct anim * anim, ImBuf * ibuf,
anim->pCodecCtx->width,
anim->pCodecCtx->height)
< 0) {
- *filter_y = 1;
+ filter_y = TRUE;
} else {
input = anim->pFrameDeinterlaced;
}
}
+ avpicture_fill((AVPicture*) anim->pFrameRGB,
+ (unsigned char*) ibuf->rect,
+ PIX_FMT_RGBA, anim->x, anim->y);
+
if (ENDIAN_ORDER == B_ENDIAN) {
int * dstStride = anim->pFrameRGB->linesize;
uint8_t** dst = anim->pFrameRGB->data;
@@ -774,150 +817,359 @@ static void ffmpeg_postprocess(struct anim * anim, ImBuf * ibuf,
}
}
}
+
+ if (filter_y) {
+ IMB_filtery(ibuf);
+ }
}
-static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
- ImBuf * ibuf;
- int frameFinished;
- AVPacket packet;
+/* decode one video frame and load the next packet into anim->packet,
+ so that we can obtain next_pts and next undecoded pts */
+
+static int ffmpeg_decode_video_frame(struct anim * anim)
+{
+ int frameFinished = 0;
+ int rval = 0;
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
+
+ anim->next_undecoded_pts = -1;
+
+ if (anim->next_packet.stream_index == anim->videoStream) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ " DECODE: cached next packet\n");
+
+ avcodec_decode_video2(anim->pCodecCtx,
+ anim->pFrame, &frameFinished,
+ &anim->next_packet);
+
+ if (frameFinished) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME DONE: "
+ "next_pts=%lld pkt_pts=%lld\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pts,
+ (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pkt_pts);
+ anim->next_pts =
+ av_get_pts_from_frame(anim->pFormatCtx,
+ anim->pFrame);
+ }
+
+ av_free_packet(&anim->next_packet);
+ anim->next_packet.stream_index = -1;
+ }
+
+ while((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ "%sREAD: strID=%d (VID: %d) dts=%lld pts=%lld "
+ "%s\n",
+ (anim->next_packet.stream_index == anim->videoStream)
+ ? "->" : " ",
+ anim->next_packet.stream_index,
+ anim->videoStream,
+ (anim->next_packet.dts == AV_NOPTS_VALUE) ? -1:
+ anim->next_packet.dts,
+ (anim->next_packet.pts == AV_NOPTS_VALUE) ? -1:
+ anim->next_packet.pts,
+ (anim->next_packet.flags & AV_PKT_FLAG_KEY) ?
+ " KEY" : "");
+ if (anim->next_packet.stream_index == anim->videoStream) {
+ if (frameFinished) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME finished, we leave\n");
+ anim->next_undecoded_pts
+ = anim->next_packet.dts;
+ break;
+ }
+
+ avcodec_decode_video2(
+ anim->pCodecCtx,
+ anim->pFrame, &frameFinished,
+ &anim->next_packet);
+
+ if (frameFinished) {
+ anim->next_pts = av_get_pts_from_frame(
+ anim->pFormatCtx, anim->pFrame);
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME DONE: next_pts=%lld "
+ "pkt_pts=%lld, guessed_pts=%lld\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pts,
+ (anim->pFrame->pkt_pts
+ == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pkt_pts,
+ anim->next_pts);
+ }
+ }
+ av_free_packet(&anim->next_packet);
+ anim->next_packet.stream_index = -1;
+ }
+
+ if (rval < 0) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_ERROR, " DECODE READ FAILED: av_read_frame() "
+ "returned error: %d\n", rval);
+ }
+ return (rval >= 0);
+}
+
+static void ffmpeg_decode_video_frame_scan(
+ struct anim * anim, int64_t pts_to_search)
+{
+ /* there seem to exist *very* silly GOP lengths out in the wild... */
+ int count = 1000;
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ "SCAN start: considering pts=%lld in search of %lld\n",
+ anim->next_pts, pts_to_search);
+
+ while (count > 0 && anim->next_pts < pts_to_search) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " WHILE: pts=%lld in search of %lld\n",
+ anim->next_pts, pts_to_search);
+ if (!ffmpeg_decode_video_frame(anim)) {
+ break;
+ }
+ count--;
+ }
+ if (count == 0) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_ERROR,
+ "SCAN failed: completely lost in stream, "
+ "bailing out at PTS=%lld, searching for PTS=%lld\n",
+ anim->next_pts, pts_to_search);
+ }
+ if (anim->next_pts == pts_to_search) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
+ } else {
+ av_log(anim->pFormatCtx,
+ AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n");
+ }
+}
+
+static int match_format(const char *name, AVFormatContext * pFormatCtx)
+{
+ const char *p;
+ int len, namelen;
+
+ const char *names = pFormatCtx->iformat->name;
+
+ if (!name || !names)
+ return 0;
+
+ namelen = strlen(name);
+ while ((p = strchr(names, ','))) {
+ len = MAX2(p - names, namelen);
+ if (!BLI_strncasecmp(name, names, len))
+ return 1;
+ names = p+1;
+ }
+ return !BLI_strcasecmp(name, names);
+}
+
+static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
+{
+ static const char * byte_seek_list [] = { "dv", "mpegts", 0 };
+ const char ** p;
+
+ if (pFormatCtx->iformat->flags & AVFMT_TS_DISCONT) {
+ return TRUE;
+ }
+
+ p = byte_seek_list;
+
+ while (*p) {
+ if (match_format(*p++, pFormatCtx)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position,
+ IMB_Timecode_Type tc) {
int64_t pts_to_search = 0;
- int pos_found = 1;
- int filter_y = 0;
- int seek_by_bytes= 0;
- int preseek_count = 0;
+ double frame_rate;
+ double pts_time_base;
+ long long st_time;
+ struct anim_index * tc_index = 0;
+ AVStream * v_st;
+ int new_frame_index;
+ int old_frame_index;
if (anim == 0) return (0);
- ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position);
- avpicture_fill((AVPicture*) anim->pFrameRGB,
- (unsigned char*) ibuf->rect,
- PIX_FMT_RGBA, anim->x, anim->y);
-
- if (position != anim->curposition + 1) {
- if (position > anim->curposition + 1
- && anim->preseek
- && position - (anim->curposition + 1) < anim->preseek) {
- while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
- if (packet.stream_index == anim->videoStream) {
- avcodec_decode_video2(
- anim->pCodecCtx,
- anim->pFrame, &frameFinished,
- &packet);
-
- if (frameFinished) {
- anim->curposition++;
- }
- }
- av_free_packet(&packet);
- if (position == anim->curposition+1) {
- break;
- }
- }
+ if (tc != IMB_TC_NONE) {
+ tc_index = IMB_anim_open_index(anim, tc);
+ }
+
+ v_st = anim->pFormatCtx->streams[anim->videoStream];
+
+ frame_rate = av_q2d(v_st->r_frame_rate);
+
+ st_time = anim->pFormatCtx->start_time;
+ pts_time_base = av_q2d(v_st->time_base);
+
+ if (tc_index) {
+ new_frame_index = IMB_indexer_get_frame_index(
+ tc_index, position);
+ old_frame_index = IMB_indexer_get_frame_index(
+ tc_index, anim->curposition);
+ pts_to_search = IMB_indexer_get_pts(
+ tc_index, new_frame_index);
+ } else {
+ pts_to_search = (long long)
+ floor(((double) position) / pts_time_base / frame_rate + 0.5);
+
+ if (st_time != AV_NOPTS_VALUE) {
+ pts_to_search += st_time / pts_time_base
+ / AV_TIME_BASE;
}
}
-/* disable seek_by_bytes for now, since bitrates are guessed wrong!
- also: MPEG2TS-seeking was fixed in later versions of ffmpeg, so problem
- is somewhat fixed by now (until we add correct timecode management code...)
-*/
-#if 0
- seek_by_bytes = !!(anim->pFormatCtx->iformat->flags & AVFMT_TS_DISCONT);
-#else
- seek_by_bytes = FALSE;
-#endif
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: looking for PTS=%lld "
+ "(pts_timebase=%g, frame_rate=%g, st_time=%lld)\n",
+ pts_to_search, pts_time_base, frame_rate, st_time);
+
+ if (anim->last_frame &&
+ anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search){
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: frame repeat: last: %lld next: %lld\n",
+ anim->last_pts, anim->next_pts);
+ IMB_refImBuf(anim->last_frame);
+ anim->curposition = position;
+ return anim->last_frame;
+ }
+
+ IMB_freeImBuf(anim->last_frame);
+
+ if (anim->next_pts <= pts_to_search &&
+ anim->next_undecoded_pts > pts_to_search) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: no seek necessary: "
+ "next: %lld next undecoded: %lld\n",
+ anim->next_pts, anim->next_undecoded_pts);
+
+ /* we are already done :) */
+
+ } else if (position > anim->curposition + 1
+ && anim->preseek
+ && !tc_index
+ && position - (anim->curposition + 1) < anim->preseek) {
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: within preseek interval (no index)\n");
+
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
+ } else if (tc_index &&
+ IMB_indexer_can_scan(tc_index, old_frame_index,
+ new_frame_index)) {
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: within preseek interval "
+ "(index tells us)\n");
- if (position != anim->curposition + 1) {
- double frame_rate =
- av_q2d(anim->pFormatCtx->streams[anim->videoStream]
- ->r_frame_rate);
- double pts_time_base = av_q2d(anim->pFormatCtx->streams[anim->videoStream]->time_base);
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
+ } else if (position != anim->curposition + 1) {
long long pos;
- long long st_time = anim->pFormatCtx->start_time;
int ret;
- if (seek_by_bytes) {
- pos = position - anim->preseek;
- if (pos < 0) {
- pos = 0;
- }
- preseek_count = position - pos;
+ if (tc_index) {
+ unsigned long long dts;
+
+ pos = IMB_indexer_get_seek_pos(
+ tc_index, new_frame_index);
+ dts = IMB_indexer_get_seek_pos_dts(
+ tc_index, new_frame_index);
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "TC INDEX seek pos = %lld\n", pos);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "TC INDEX seek dts = %lld\n", dts);
- pos *= anim->pFormatCtx->bit_rate / frame_rate;
- pos /= 8;
+ if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "... using BYTE pos\n");
+
+ ret = av_seek_frame(anim->pFormatCtx,
+ -1,
+ pos, AVSEEK_FLAG_BYTE);
+ av_update_cur_dts(anim->pFormatCtx, v_st, dts);
+ } else {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "... using DTS pos\n");
+ ret = av_seek_frame(anim->pFormatCtx,
+ anim->videoStream,
+ dts, AVSEEK_FLAG_BACKWARD);
+ }
} else {
pos = (long long) (position - anim->preseek)
* AV_TIME_BASE / frame_rate;
if (pos < 0) {
pos = 0;
}
-
+
if (st_time != AV_NOPTS_VALUE) {
pos += st_time;
}
- }
- ret = av_seek_frame(anim->pFormatCtx, -1,
- pos,
- AVSEEK_FLAG_BACKWARD | (
- seek_by_bytes
- ? AVSEEK_FLAG_ANY
- | AVSEEK_FLAG_BYTE : 0));
- if (ret < 0) {
- fprintf(stderr, "error while seeking: %d\n", ret);
+ ret = av_seek_frame(anim->pFormatCtx, -1,
+ pos, AVSEEK_FLAG_BACKWARD);
}
- pts_to_search = (long long)
- (((double) position) / pts_time_base / frame_rate);
- if (st_time != AV_NOPTS_VALUE) {
- pts_to_search += st_time / pts_time_base/ AV_TIME_BASE;
+ if (ret < 0) {
+ av_log(anim->pFormatCtx, AV_LOG_ERROR,
+ "FETCH: "
+ "error while seeking to DTS = %lld "
+ "(frameno = %d, PTS = %lld): errcode = %d\n",
+ pos, position, pts_to_search, ret);
}
- pos_found = 0;
avcodec_flush_buffers(anim->pCodecCtx);
- }
- while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
- if(packet.stream_index == anim->videoStream) {
- avcodec_decode_video2(anim->pCodecCtx,
- anim->pFrame, &frameFinished,
- &packet);
+ anim->next_pts = -1;
- if (seek_by_bytes && preseek_count > 0) {
- preseek_count--;
- }
+ if (anim->next_packet.stream_index == anim->videoStream) {
+ av_free_packet(&anim->next_packet);
+ anim->next_packet.stream_index = -1;
+ }
- if (frameFinished && !pos_found) {
- if (seek_by_bytes) {
- if (!preseek_count) {
- pos_found = 1;
- anim->curposition = position;
- }
- } else {
- if (packet.dts >= pts_to_search) {
- pos_found = 1;
- anim->curposition = position;
- }
- }
- }
+ /* memset(anim->pFrame,...) ?? */
- if(frameFinished && pos_found == 1) {
- ffmpeg_postprocess(anim, ibuf, &filter_y);
- av_free_packet(&packet);
- break;
- }
+ if (ret >= 0) {
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
}
-
- av_free_packet(&packet);
+ } else if (position == 0 && anim->curposition == -1) {
+ /* first frame without seeking special case... */
+ ffmpeg_decode_video_frame(anim);
}
- if (filter_y && ibuf) {
- IMB_filtery(ibuf);
- }
+ anim->last_frame = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
- ibuf->profile = IB_PROFILE_SRGB;
+ ffmpeg_postprocess(anim);
- return(ibuf);
+ anim->last_pts = anim->next_pts;
+
+ ffmpeg_decode_video_frame(anim);
+
+ anim->curposition = position;
+
+ IMB_refImBuf(anim->last_frame);
+
+ return anim->last_frame;
}
static void free_anim_ffmpeg(struct anim * anim) {
@@ -934,6 +1186,10 @@ static void free_anim_ffmpeg(struct anim * anim) {
}
av_free(anim->pFrameDeinterlaced);
sws_freeContext(anim->img_convert_ctx);
+ IMB_freeImBuf(anim->last_frame);
+ if (anim->next_packet.stream_index != -1) {
+ av_free_packet(&anim->next_packet);
+ }
}
anim->duration = 0;
}
@@ -1063,16 +1319,19 @@ struct ImBuf * IMB_anim_previewframe(struct anim * anim) {
struct ImBuf * ibuf = NULL;
int position = 0;
- ibuf = IMB_anim_absolute(anim, 0);
+ ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (ibuf) {
IMB_freeImBuf(ibuf);
position = anim->duration / 2;
- ibuf = IMB_anim_absolute(anim, position);
+ ibuf = IMB_anim_absolute(anim, position, IMB_TC_NONE,
+ IMB_PROXY_NONE);
}
return ibuf;
}
-struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
+struct ImBuf * IMB_anim_absolute(struct anim * anim, int position,
+ IMB_Timecode_Type tc,
+ IMB_Proxy_Size preview_size) {
struct ImBuf * ibuf = NULL;
char head[256], tail[256];
unsigned short digits;
@@ -1095,6 +1354,18 @@ struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
if (position < 0) return(NULL);
if (position >= anim->duration) return(NULL);
+ if (preview_size != IMB_PROXY_NONE) {
+ struct anim * proxy = IMB_anim_open_proxy(anim, preview_size);
+
+ if (proxy) {
+ position = IMB_anim_index_get_frame_index(
+ anim, tc, position);
+ return IMB_anim_absolute(
+ proxy, position,
+ IMB_TC_NONE, IMB_PROXY_NONE);
+ }
+ }
+
switch(anim->curtype) {
case ANIM_SEQUENCE:
pic = an_stringdec(anim->first, head, tail, &digits);
@@ -1127,7 +1398,7 @@ struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
#endif
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- ibuf = ffmpeg_fetchibuf(anim, position);
+ ibuf = ffmpeg_fetchibuf(anim, position, tc);
if (ibuf)
anim->curposition = position;
filter_y = 0; /* done internally */
@@ -1151,8 +1422,29 @@ struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
/***/
-int IMB_anim_get_duration(struct anim *anim) {
- return anim->duration;
+int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) {
+ struct anim_index * idx;
+ if (tc == IMB_TC_NONE) {
+ return anim->duration;
+ }
+
+ idx = IMB_anim_open_index(anim, tc);
+ if (!idx) {
+ return anim->duration;
+ }
+
+ return IMB_indexer_get_duration(idx);
+}
+
+int IMB_anim_get_fps(struct anim * anim,
+ short * frs_sec, float * frs_sec_base)
+{
+ if (anim->frs_sec) {
+ *frs_sec = anim->frs_sec;
+ *frs_sec_base = anim->frs_sec_base;
+ return TRUE;
+ }
+ return FALSE;
}
void IMB_anim_set_preseek(struct anim * anim, int preseek)
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index 971658ff482..44e029bd7ce 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -1426,12 +1426,12 @@ void DirectDrawSurface::printInfo() const
if (header.flags & DDSD_LINEARSIZE) printf("\tDDSD_LINEARSIZE\n");
if (header.flags & DDSD_MIPMAPCOUNT) printf("\tDDSD_MIPMAPCOUNT\n");
- printf("Height: %d\n", header.height);
- printf("Width: %d\n", header.width);
- printf("Depth: %d\n", header.depth);
- if (header.flags & DDSD_PITCH) printf("Pitch: %d\n", header.pitch);
- else if (header.flags & DDSD_LINEARSIZE) printf("Linear size: %d\n", header.pitch);
- printf("Mipmap count: %d\n", header.mipmapcount);
+ printf("Height: %u\n", header.height);
+ printf("Width: %u\n", header.width);
+ printf("Depth: %u\n", header.depth);
+ if (header.flags & DDSD_PITCH) printf("Pitch: %u\n", header.pitch);
+ else if (header.flags & DDSD_LINEARSIZE) printf("Linear size: %u\n", header.pitch);
+ printf("Mipmap count: %u\n", header.mipmapcount);
printf("Pixel Format:\n");
printf("\tFlags: 0x%.8X\n", header.pf.flags);
@@ -1468,7 +1468,7 @@ void DirectDrawSurface::printInfo() const
}
else
{
- printf("\tBit count: %d\n", header.pf.bitcount);
+ printf("\tBit count: %u\n", header.pf.bitcount);
}
printf("\tRed mask: 0x%.8X\n", header.pf.rmask);
@@ -1522,7 +1522,7 @@ void DirectDrawSurface::printInfo() const
if (header.reserved[7] == FOURCC_UVER)
{
- printf("User Version: %d\n", header.reserved[8]);
+ printf("User Version: %u\n", header.reserved[8]);
}
}
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 7f1eef80318..2677913caed 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -1,5 +1,7 @@
/*
*
+ * $Id$
+ *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
new file mode 100644
index 00000000000..3528318ba81
--- /dev/null
+++ b/source/blender/imbuf/intern/indexer.c
@@ -0,0 +1,1142 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Peter Schlaile <peter [at] schlaile [dot] de> 2011
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "IMB_indexer.h"
+#include "IMB_anim.h"
+#include "AVI_avi.h"
+#include "imbuf.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_math_base.h"
+#include "BLI_string.h"
+#include "MEM_guardedalloc.h"
+#include "DNA_userdef_types.h"
+#include "BKE_global.h"
+#include <stdlib.h>
+
+#ifdef WITH_FFMPEG
+
+#include "ffmpeg_compat.h"
+
+#endif //WITH_FFMPEG
+
+
+static char magic[] = "BlenMIdx";
+static char temp_ext [] = "_part";
+
+static int proxy_sizes[] = { IMB_PROXY_25, IMB_PROXY_50, IMB_PROXY_75,
+ IMB_PROXY_100 };
+static float proxy_fac[] = { 0.25, 0.50, 0.75, 1.00 };
+
+#ifdef WITH_FFMPEG
+static int tc_types[] = { IMB_TC_RECORD_RUN, IMB_TC_FREE_RUN,
+ IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN };
+#endif
+
+#define INDEX_FILE_VERSION 1
+
+/* ----------------------------------------------------------------------
+ - special indexers
+ ----------------------------------------------------------------------
+ */
+
+extern void IMB_indexer_dv_new(anim_index_builder * idx);
+
+
+/* ----------------------------------------------------------------------
+ - time code index functions
+ ---------------------------------------------------------------------- */
+
+anim_index_builder * IMB_index_builder_create(const char * name)
+{
+
+ anim_index_builder * rv
+ = MEM_callocN( sizeof(struct anim_index_builder),
+ "index builder");
+
+ fprintf(stderr, "Starting work on index: %s\n", name);
+
+ BLI_strncpy(rv->name, name, sizeof(rv->name));
+ BLI_strncpy(rv->temp_name, name, sizeof(rv->temp_name));
+
+ strcat(rv->temp_name, temp_ext);
+
+ BLI_make_existing_file(rv->temp_name);
+
+ rv->fp = fopen(rv->temp_name, "w");
+
+ if (!rv->fp) {
+ fprintf(stderr, "Couldn't open index target: %s! "
+ "Index build broken!\n", rv->temp_name);
+ MEM_freeN(rv);
+ return NULL;
+ }
+
+ fprintf(rv->fp, "%s%c%.3d", magic, (ENDIAN_ORDER==B_ENDIAN)?'V':'v',
+ INDEX_FILE_VERSION);
+
+ return rv;
+}
+
+void IMB_index_builder_add_entry(anim_index_builder * fp,
+ int frameno,unsigned long long seek_pos,
+ unsigned long long seek_pos_dts,
+ unsigned long long pts)
+{
+ fwrite(&frameno, sizeof(int), 1, fp->fp);
+ fwrite(&seek_pos, sizeof(unsigned long long), 1, fp->fp);
+ fwrite(&seek_pos_dts, sizeof(unsigned long long), 1, fp->fp);
+ fwrite(&pts, sizeof(unsigned long long), 1, fp->fp);
+}
+
+void IMB_index_builder_proc_frame(anim_index_builder * fp,
+ unsigned char * buffer,
+ int data_size,
+ int frameno, unsigned long long seek_pos,
+ unsigned long long seek_pos_dts,
+ unsigned long long pts)
+{
+ if (fp->proc_frame) {
+ anim_index_entry e;
+ e.frameno = frameno;
+ e.seek_pos = seek_pos;
+ e.seek_pos_dts = seek_pos_dts;
+ e.pts = pts;
+
+ fp->proc_frame(fp, buffer, data_size, &e);
+ } else {
+ IMB_index_builder_add_entry(fp, frameno, seek_pos,
+ seek_pos_dts, pts);
+ }
+}
+
+void IMB_index_builder_finish(anim_index_builder * fp, int rollback)
+{
+ if (fp->delete_priv_data) {
+ fp->delete_priv_data(fp);
+ }
+
+ fclose(fp->fp);
+
+ if (rollback) {
+ unlink(fp->temp_name);
+ } else {
+ rename(fp->temp_name, fp->name);
+ }
+
+ MEM_freeN(fp);
+}
+
+struct anim_index * IMB_indexer_open(const char * name)
+{
+ char header[13];
+ struct anim_index * idx;
+ FILE * fp = fopen(name, "rb");
+ int i;
+
+ if (!fp) {
+ return 0;
+ }
+
+ if (fread(header, 12, 1, fp) != 1) {
+ fclose(fp);
+ return 0;
+ }
+
+ header[12] = 0;
+
+ if (memcmp(header, magic, 8) != 0) {
+ fclose(fp);
+ return 0;
+ }
+
+ if (atoi(header+9) != INDEX_FILE_VERSION) {
+ fclose(fp);
+ return 0;
+ }
+
+ idx = MEM_callocN( sizeof(struct anim_index), "anim_index");
+
+ BLI_strncpy(idx->name, name, sizeof(idx->name));
+
+ fseek(fp, 0, SEEK_END);
+
+ idx->num_entries = (ftell(fp) - 12)
+ / (sizeof(int) // framepos
+ + sizeof(unsigned long long) // seek_pos
+ + sizeof(unsigned long long) // seek_pos_dts
+ + sizeof(unsigned long long) // pts
+ );
+
+ fseek(fp, 12, SEEK_SET);
+
+ idx->entries = MEM_callocN( sizeof(struct anim_index_entry)
+ * idx->num_entries, "anim_index_entries");
+
+ for (i = 0; i < idx->num_entries; i++) {
+ fread(&idx->entries[i].frameno,
+ sizeof(int), 1, fp);
+ fread(&idx->entries[i].seek_pos,
+ sizeof(unsigned long long), 1, fp);
+ fread(&idx->entries[i].seek_pos_dts,
+ sizeof(unsigned long long), 1, fp);
+ fread(&idx->entries[i].pts,
+ sizeof(unsigned long long), 1, fp);
+ }
+
+ if (((ENDIAN_ORDER == B_ENDIAN) != (header[8] == 'V'))) {
+ for (i = 0; i < idx->num_entries; i++) {
+ SWITCH_INT(idx->entries[i].frameno);
+ SWITCH_INT64(idx->entries[i].seek_pos);
+ SWITCH_INT64(idx->entries[i].seek_pos_dts);
+ SWITCH_INT64(idx->entries[i].pts);
+ }
+ }
+
+ fclose(fp);
+
+ return idx;
+}
+
+unsigned long long IMB_indexer_get_seek_pos(
+ struct anim_index * idx, int frame_index)
+{
+ if (frame_index < 0) {
+ frame_index = 0;
+ }
+ if (frame_index >= idx->num_entries) {
+ frame_index = idx->num_entries - 1;
+ }
+ return idx->entries[frame_index].seek_pos;
+}
+
+unsigned long long IMB_indexer_get_seek_pos_dts(
+ struct anim_index * idx, int frame_index)
+{
+ if (frame_index < 0) {
+ frame_index = 0;
+ }
+ if (frame_index >= idx->num_entries) {
+ frame_index = idx->num_entries - 1;
+ }
+ return idx->entries[frame_index].seek_pos_dts;
+}
+
+int IMB_indexer_get_frame_index(struct anim_index * idx, int frameno)
+{
+ int len = idx->num_entries;
+ int half;
+ int middle;
+ int first = 0;
+
+ /* bsearch (lower bound) the right index */
+
+ while (len > 0) {
+ half = len >> 1;
+ middle = first;
+
+ middle += half;
+
+ if (idx->entries[middle].frameno < frameno) {
+ first = middle;
+ ++first;
+ len = len - half - 1;
+ } else {
+ len = half;
+ }
+ }
+
+ if (first == idx->num_entries) {
+ return idx->num_entries - 1;
+ } else {
+ return first;
+ }
+}
+
+unsigned long long IMB_indexer_get_pts(struct anim_index * idx,
+ int frame_index)
+{
+ if (frame_index < 0) {
+ frame_index = 0;
+ }
+ if (frame_index >= idx->num_entries) {
+ frame_index = idx->num_entries - 1;
+ }
+ return idx->entries[frame_index].pts;
+}
+
+int IMB_indexer_get_duration(struct anim_index * idx)
+{
+ if (idx->num_entries == 0) {
+ return 0;
+ }
+ return idx->entries[idx->num_entries-1].frameno + 1;
+}
+
+int IMB_indexer_can_scan(struct anim_index * idx,
+ int old_frame_index, int new_frame_index)
+{
+ /* makes only sense, if it is the same I-Frame and we are not
+ trying to run backwards in time... */
+ return (IMB_indexer_get_seek_pos(idx, old_frame_index)
+ == IMB_indexer_get_seek_pos(idx, new_frame_index) &&
+ old_frame_index < new_frame_index);
+}
+
+void IMB_indexer_close(struct anim_index * idx)
+{
+ MEM_freeN(idx->entries);
+ MEM_freeN(idx);
+}
+
+int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
+{
+ switch (pr_size) {
+ case IMB_PROXY_NONE: /* if we got here, something is broken anyways,
+ so sane defaults... */
+ return 0;
+ case IMB_PROXY_25:
+ return 0;
+ case IMB_PROXY_50:
+ return 1;
+ case IMB_PROXY_75:
+ return 2;
+ case IMB_PROXY_100:
+ return 3;
+ default:
+ return 0;
+ };
+ return 0;
+}
+
+int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
+{
+ switch (tc) {
+ case IMB_TC_NONE: /* if we got here, something is broken anyways,
+ so sane defaults... */
+ return 0;
+ case IMB_TC_RECORD_RUN:
+ return 0;
+ case IMB_TC_FREE_RUN:
+ return 1;
+ case IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN:
+ return 2;
+ default:
+ return 0;
+ };
+ return 0;
+}
+
+
+/* ----------------------------------------------------------------------
+ - rebuild helper functions
+ ---------------------------------------------------------------------- */
+
+static void get_index_dir(struct anim * anim, char * index_dir)
+{
+ if (!anim->index_dir[0]) {
+ char fname[FILE_MAXFILE];
+ BLI_strncpy(index_dir, anim->name, FILE_MAXDIR);
+ BLI_splitdirstring(index_dir, fname);
+ BLI_join_dirfile(index_dir, FILE_MAXDIR, index_dir, "BL_proxy");
+ BLI_join_dirfile(index_dir, FILE_MAXDIR, index_dir, fname);
+ } else {
+ BLI_strncpy(index_dir, anim->index_dir, FILE_MAXDIR);
+ }
+}
+
+static void get_proxy_filename(struct anim * anim, IMB_Proxy_Size preview_size,
+ char * fname, int temp)
+{
+ char index_dir[FILE_MAXDIR];
+ int i = IMB_proxy_size_to_array_index(preview_size);
+
+ char proxy_name[256];
+ char proxy_temp_name[256];
+ char stream_suffix[20];
+
+ stream_suffix[0] = 0;
+
+ if (anim->streamindex > 0) {
+ BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
+ }
+
+ BLI_snprintf(proxy_name, 256, "proxy_%d%s.avi",
+ (int) (proxy_fac[i] * 100), stream_suffix);
+ BLI_snprintf(proxy_temp_name, 256, "proxy_%d%s_part.avi",
+ (int) (proxy_fac[i] * 100), stream_suffix);
+
+ get_index_dir(anim, index_dir);
+
+ BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir,
+ temp ? proxy_temp_name : proxy_name);
+}
+
+static void get_tc_filename(struct anim * anim, IMB_Timecode_Type tc,
+ char * fname)
+{
+ char index_dir[FILE_MAXDIR];
+ int i = IMB_timecode_to_array_index(tc);
+ const char * index_names[] = {
+ "record_run%s.blen_tc", "free_run%s.blen_tc",
+ "interp_free_run%s.blen_tc" };
+
+ char stream_suffix[20];
+ char index_name[256];
+
+ stream_suffix[0] = 0;
+
+ if (anim->streamindex > 0) {
+ BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
+ }
+
+ BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
+
+ get_index_dir(anim, index_dir);
+
+ BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR,
+ index_dir, index_name);
+}
+
+/* ----------------------------------------------------------------------
+ - ffmpeg rebuilder
+ ---------------------------------------------------------------------- */
+
+#ifdef WITH_FFMPEG
+
+struct proxy_output_ctx {
+ AVFormatContext* of;
+ AVStream* st;
+ AVCodecContext* c;
+ AVCodec* codec;
+ struct SwsContext * sws_ctx;
+ AVFrame* frame;
+ uint8_t* video_buffer;
+ int video_buffersize;
+ int cfra;
+ int proxy_size;
+ int orig_height;
+ struct anim * anim;
+};
+
+// work around stupid swscaler 16 bytes alignment bug...
+
+static int round_up(int x, int mod)
+{
+ return x + ((mod - (x % mod)) % mod);
+}
+
+static struct proxy_output_ctx * alloc_proxy_output_ffmpeg(
+ struct anim * anim,
+ AVStream * st, int proxy_size, int width, int height,
+ int quality)
+{
+ struct proxy_output_ctx * rv = MEM_callocN(
+ sizeof(struct proxy_output_ctx), "alloc_proxy_output");
+
+ char fname[FILE_MAXDIR+FILE_MAXFILE];
+
+ // JPEG requires this
+ width = round_up(width, 8);
+ height = round_up(height, 8);
+
+ rv->proxy_size = proxy_size;
+ rv->anim = anim;
+
+ get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE);
+ BLI_make_existing_file(fname);
+
+ rv->of = avformat_alloc_context();
+ rv->of->oformat = av_guess_format("avi", NULL, NULL);
+
+ BLI_snprintf(rv->of->filename, sizeof(rv->of->filename), "%s", fname);
+
+ fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename);
+
+ rv->st = av_new_stream(rv->of, 0);
+ rv->c = rv->st->codec;
+ rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
+ rv->c->codec_id = CODEC_ID_MJPEG;
+ rv->c->width = width;
+ rv->c->height = height;
+
+ rv->of->oformat->video_codec = rv->c->codec_id;
+ rv->codec = avcodec_find_encoder(rv->c->codec_id);
+
+ if (!rv->codec) {
+ fprintf(stderr, "No ffmpeg MJPEG encoder available? "
+ "Proxy not built!\n");
+ av_free(rv->of);
+ return NULL;
+ }
+
+ if (rv->codec->pix_fmts) {
+ rv->c->pix_fmt = rv->codec->pix_fmts[0];
+ } else {
+ rv->c->pix_fmt = PIX_FMT_YUVJ420P;
+ }
+
+ rv->c->sample_aspect_ratio
+ = rv->st->sample_aspect_ratio
+ = st->codec->sample_aspect_ratio;
+
+ rv->c->time_base.den = 25;
+ rv->c->time_base.num = 1;
+ rv->st->time_base = rv->c->time_base;
+
+ if (rv->of->flags & AVFMT_GLOBALHEADER) {
+ rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ }
+
+ if (av_set_parameters(rv->of, NULL) < 0) {
+ fprintf(stderr, "Couldn't set output parameters? "
+ "Proxy not built!\n");
+ av_free(rv->of);
+ return 0;
+ }
+
+ if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) {
+ fprintf(stderr, "Couldn't open outputfile! "
+ "Proxy not built!\n");
+ av_free(rv->of);
+ return 0;
+ }
+
+ avcodec_open(rv->c, rv->codec);
+
+ rv->video_buffersize = 2000000;
+ rv->video_buffer = (uint8_t*)MEM_mallocN(
+ rv->video_buffersize, "FFMPEG video buffer");
+
+ rv->orig_height = st->codec->height;
+
+ if (st->codec->width != width || st->codec->height != height
+ || st->codec->pix_fmt != rv->c->pix_fmt) {
+ rv->frame = avcodec_alloc_frame();
+ avpicture_fill((AVPicture*) rv->frame,
+ MEM_mallocN(avpicture_get_size(
+ rv->c->pix_fmt,
+ round_up(width, 16), height),
+ "alloc proxy output frame"),
+ rv->c->pix_fmt, round_up(width, 16), height);
+
+ rv->sws_ctx = sws_getContext(
+ st->codec->width,
+ st->codec->height,
+ st->codec->pix_fmt,
+ width, height,
+ rv->c->pix_fmt,
+ SWS_FAST_BILINEAR | SWS_PRINT_INFO,
+ NULL, NULL, NULL);
+ }
+
+ av_write_header(rv->of);
+
+ return rv;
+}
+
+static int add_to_proxy_output_ffmpeg(
+ struct proxy_output_ctx * ctx, AVFrame * frame)
+{
+ int outsize = 0;
+
+ if (!ctx) {
+ return 0;
+ }
+
+ if (ctx->sws_ctx && frame &&
+ (frame->data[0] || frame->data[1] ||
+ frame->data[2] || frame->data[3])) {
+ sws_scale(ctx->sws_ctx, (const uint8_t * const*) frame->data,
+ frame->linesize, 0, ctx->orig_height,
+ ctx->frame->data, ctx->frame->linesize);
+ }
+
+ frame = ctx->sws_ctx ? (frame ? ctx->frame : 0) : frame;
+
+ if (frame) {
+ frame->pts = ctx->cfra++;
+ }
+
+ outsize = avcodec_encode_video(
+ ctx->c, ctx->video_buffer, ctx->video_buffersize,
+ frame);
+
+ if (outsize < 0) {
+ fprintf(stderr, "Error encoding proxy frame %d for '%s'\n",
+ ctx->cfra - 1, ctx->of->filename);
+ return 0;
+ }
+
+ if (outsize != 0) {
+ AVPacket packet;
+ av_init_packet(&packet);
+
+ if (ctx->c->coded_frame->pts != AV_NOPTS_VALUE) {
+ packet.pts = av_rescale_q(ctx->c->coded_frame->pts,
+ ctx->c->time_base,
+ ctx->st->time_base);
+ }
+ if (ctx->c->coded_frame->key_frame)
+ packet.flags |= AV_PKT_FLAG_KEY;
+
+ packet.stream_index = ctx->st->index;
+ packet.data = ctx->video_buffer;
+ packet.size = outsize;
+
+ if (av_interleaved_write_frame(ctx->of, &packet) != 0) {
+ fprintf(stderr, "Error writing proxy frame %d "
+ "into '%s'\n", ctx->cfra - 1,
+ ctx->of->filename);
+ return 0;
+ }
+
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void free_proxy_output_ffmpeg(struct proxy_output_ctx * ctx,
+ int rollback)
+{
+ int i;
+ char fname[FILE_MAXDIR+FILE_MAXFILE];
+ char fname_tmp[FILE_MAXDIR+FILE_MAXFILE];
+
+ if (!ctx) {
+ return;
+ }
+
+ if (!rollback) {
+ while (add_to_proxy_output_ffmpeg(ctx, NULL)) ;
+ }
+
+ avcodec_flush_buffers(ctx->c);
+
+ av_write_trailer(ctx->of);
+
+ avcodec_close(ctx->c);
+
+ for (i = 0; i < ctx->of->nb_streams; i++) {
+ if (&ctx->of->streams[i]) {
+ av_freep(&ctx->of->streams[i]);
+ }
+ }
+
+ if (ctx->of->oformat) {
+ if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
+ avio_close(ctx->of->pb);
+ }
+ }
+ av_free(ctx->of);
+
+ MEM_freeN(ctx->video_buffer);
+
+ if (ctx->sws_ctx) {
+ sws_freeContext(ctx->sws_ctx);
+
+ MEM_freeN(ctx->frame->data[0]);
+ av_free(ctx->frame);
+ }
+
+ get_proxy_filename(ctx->anim, ctx->proxy_size,
+ fname_tmp, TRUE);
+
+ if (rollback) {
+ unlink(fname_tmp);
+ } else {
+ get_proxy_filename(ctx->anim, ctx->proxy_size,
+ fname, FALSE);
+ rename(fname_tmp, fname);
+ }
+
+ MEM_freeN(ctx);
+}
+
+
+static int index_rebuild_ffmpeg(struct anim * anim,
+ IMB_Timecode_Type tcs_in_use,
+ IMB_Proxy_Size proxy_sizes_in_use,
+ int quality,
+ short *stop, short *do_update,
+ float *progress)
+{
+ int i, videoStream;
+ unsigned long long seek_pos = 0;
+ unsigned long long last_seek_pos = 0;
+ unsigned long long seek_pos_dts = 0;
+ unsigned long long seek_pos_pts = 0;
+ unsigned long long last_seek_pos_dts = 0;
+ unsigned long long start_pts = 0;
+ double frame_rate;
+ double pts_time_base;
+ int frameno = 0;
+ int start_pts_set = FALSE;
+
+ AVFormatContext *iFormatCtx;
+ AVCodecContext *iCodecCtx;
+ AVCodec *iCodec;
+ AVStream *iStream;
+ AVFrame* in_frame = 0;
+ AVPacket next_packet;
+ int streamcount;
+
+ struct proxy_output_ctx * proxy_ctx[IMB_PROXY_MAX_SLOT];
+ anim_index_builder * indexer [IMB_TC_MAX_SLOT];
+
+ int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
+ int num_indexers = IMB_TC_MAX_SLOT;
+ uint64_t stream_size;
+
+ memset(proxy_ctx, 0, sizeof(proxy_ctx));
+ memset(indexer, 0, sizeof(indexer));
+
+ if(av_open_input_file(&iFormatCtx, anim->name, NULL, 0, NULL) != 0) {
+ return 0;
+ }
+
+ if (av_find_stream_info(iFormatCtx) < 0) {
+ av_close_input_file(iFormatCtx);
+ return 0;
+ }
+
+ streamcount = anim->streamindex;
+
+ /* Find the video stream */
+ videoStream = -1;
+ for (i = 0; i < iFormatCtx->nb_streams; i++)
+ if(iFormatCtx->streams[i]->codec->codec_type
+ == AVMEDIA_TYPE_VIDEO) {
+ if (streamcount > 0) {
+ streamcount--;
+ continue;
+ }
+ videoStream = i;
+ break;
+ }
+
+ if (videoStream == -1) {
+ av_close_input_file(iFormatCtx);
+ return 0;
+ }
+
+ iStream = iFormatCtx->streams[videoStream];
+ iCodecCtx = iStream->codec;
+
+ iCodec = avcodec_find_decoder(iCodecCtx->codec_id);
+
+ if (iCodec == NULL) {
+ av_close_input_file(iFormatCtx);
+ return 0;
+ }
+
+ iCodecCtx->workaround_bugs = 1;
+
+ if (avcodec_open(iCodecCtx, iCodec) < 0) {
+ av_close_input_file(iFormatCtx);
+ return 0;
+ }
+
+ in_frame = avcodec_alloc_frame();
+
+ stream_size = avio_size(iFormatCtx->pb);
+
+ for (i = 0; i < num_proxy_sizes; i++) {
+ if (proxy_sizes_in_use & proxy_sizes[i]) {
+ proxy_ctx[i] = alloc_proxy_output_ffmpeg(
+ anim, iStream, proxy_sizes[i],
+ iCodecCtx->width * proxy_fac[i],
+ iCodecCtx->height * proxy_fac[i],
+ quality);
+ if (!proxy_ctx[i]) {
+ proxy_sizes_in_use &= ~proxy_sizes[i];
+ }
+ }
+ }
+
+ for (i = 0; i < num_indexers; i++) {
+ if (tcs_in_use & tc_types[i]) {
+ char fname[FILE_MAXDIR+FILE_MAXFILE];
+
+ get_tc_filename(anim, tc_types[i], fname);
+
+ indexer[i] = IMB_index_builder_create(fname);
+ if (!indexer[i]) {
+ tcs_in_use &= ~tc_types[i];
+ }
+ }
+ }
+
+ frame_rate = av_q2d(iStream->r_frame_rate);
+ pts_time_base = av_q2d(iStream->time_base);
+
+ while(av_read_frame(iFormatCtx, &next_packet) >= 0) {
+ int frame_finished = 0;
+ float next_progress = ((int)floor(((double) next_packet.pos) * 100 /
+ ((double) stream_size)+0.5)) / 100;
+
+ if (*progress != next_progress) {
+ *progress = next_progress;
+ *do_update = 1;
+ }
+
+ if (*stop) {
+ av_free_packet(&next_packet);
+ break;
+ }
+
+ if (next_packet.stream_index == videoStream) {
+ if (next_packet.flags & AV_PKT_FLAG_KEY) {
+ last_seek_pos = seek_pos;
+ last_seek_pos_dts = seek_pos_dts;
+ seek_pos = next_packet.pos;
+ seek_pos_dts = next_packet.dts;
+ seek_pos_pts = next_packet.pts;
+ }
+
+ avcodec_decode_video2(
+ iCodecCtx, in_frame, &frame_finished,
+ &next_packet);
+ }
+
+ if (frame_finished) {
+ unsigned long long s_pos = seek_pos;
+ unsigned long long s_dts = seek_pos_dts;
+ unsigned long long pts
+ = av_get_pts_from_frame(iFormatCtx, in_frame);
+
+ for (i = 0; i < num_proxy_sizes; i++) {
+ add_to_proxy_output_ffmpeg(
+ proxy_ctx[i], in_frame);
+ }
+
+ if (!start_pts_set) {
+ start_pts = pts;
+ start_pts_set = TRUE;
+ }
+
+ frameno = (pts - start_pts)
+ * pts_time_base * frame_rate;
+
+ /* decoding starts *always* on I-Frames,
+ so: P-Frames won't work, even if all the
+ information is in place, when we seek
+ to the I-Frame presented *after* the P-Frame,
+ but located before the P-Frame within
+ the stream */
+
+ if (pts < seek_pos_pts) {
+ s_pos = last_seek_pos;
+ s_dts = last_seek_pos_dts;
+ }
+
+ for (i = 0; i < num_indexers; i++) {
+ if (tcs_in_use & tc_types[i]) {
+ IMB_index_builder_proc_frame(
+ indexer[i],
+ next_packet.data,
+ next_packet.size,
+ frameno, s_pos, s_dts, pts);
+ }
+ }
+ }
+ av_free_packet(&next_packet);
+ }
+
+ for (i = 0; i < num_indexers; i++) {
+ if (tcs_in_use & tc_types[i]) {
+ IMB_index_builder_finish(indexer[i], *stop);
+ }
+ }
+
+ for (i = 0; i < num_proxy_sizes; i++) {
+ if (proxy_sizes_in_use & proxy_sizes[i]) {
+ free_proxy_output_ffmpeg(proxy_ctx[i], *stop);
+ }
+ }
+
+ av_free(in_frame);
+
+ return 1;
+}
+
+#endif
+
+/* ----------------------------------------------------------------------
+ - internal AVI (fallback) rebuilder
+ ---------------------------------------------------------------------- */
+
+static AviMovie * alloc_proxy_output_avi(
+ struct anim * anim, char * filename, int width, int height,
+ int quality)
+{
+ int x, y;
+ AviFormat format;
+ double framerate;
+ AviMovie * avi;
+ short frs_sec = 25; /* it doesn't really matter for proxies,
+ but sane defaults help anyways...*/
+ float frs_sec_base = 1.0;
+
+ IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base);
+
+ x = width;
+ y = height;
+
+ framerate= (double) frs_sec / (double) frs_sec_base;
+
+ avi = MEM_mallocN (sizeof(AviMovie), "avimovie");
+
+ format = AVI_FORMAT_MJPEG;
+
+ if (AVI_open_compress (filename, avi, 1, format) != AVI_ERROR_NONE) {
+ MEM_freeN(avi);
+ return 0;
+ }
+
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
+
+ avi->interlace= 0;
+ avi->odd_fields= 0;
+
+ return avi;
+}
+
+static void index_rebuild_fallback(struct anim * anim,
+ IMB_Timecode_Type UNUSED(tcs_in_use),
+ IMB_Proxy_Size proxy_sizes_in_use,
+ int quality,
+ short *stop, short *do_update,
+ float *progress)
+{
+ int cnt = IMB_anim_get_duration(anim, IMB_TC_NONE);
+ int i, pos;
+ AviMovie * proxy_ctx[IMB_PROXY_MAX_SLOT];
+ char fname[FILE_MAXDIR+FILE_MAXFILE];
+ char fname_tmp[FILE_MAXDIR+FILE_MAXFILE];
+
+ memset(proxy_ctx, 0, sizeof(proxy_ctx));
+
+ /* since timecode indices only work with ffmpeg right now,
+ don't know a sensible fallback here...
+
+ so no proxies, no game to play...
+ */
+ if (proxy_sizes_in_use == IMB_PROXY_NONE) {
+ return;
+ }
+
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
+ if (proxy_sizes_in_use & proxy_sizes[i]) {
+ char fname[FILE_MAXDIR+FILE_MAXFILE];
+
+ get_proxy_filename(anim, proxy_sizes[i], fname, TRUE);
+ BLI_make_existing_file(fname);
+
+ proxy_ctx[i] = alloc_proxy_output_avi(
+ anim, fname,
+ anim->x * proxy_fac[i],
+ anim->y * proxy_fac[i],
+ quality);
+ }
+ }
+
+ for (pos = 0; pos < cnt; pos++) {
+ struct ImBuf * ibuf = IMB_anim_absolute(
+ anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
+ int next_progress = (int) ((double) pos / (double) cnt);
+
+ if (*progress != next_progress) {
+ *progress = next_progress;
+ *do_update = 1;
+ }
+
+ if (*stop) {
+ break;
+ }
+
+ IMB_flipy(ibuf);
+
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
+ if (proxy_sizes_in_use & proxy_sizes[i]) {
+ int x = anim->x * proxy_fac[i];
+ int y = anim->y * proxy_fac[i];
+
+ struct ImBuf * s_ibuf = IMB_scalefastImBuf(
+ ibuf, x, y);
+
+ IMB_convert_rgba_to_abgr(s_ibuf);
+
+ AVI_write_frame (proxy_ctx[i], pos,
+ AVI_FORMAT_RGB32,
+ s_ibuf->rect, x * y * 4);
+
+ /* note that libavi free's the buffer... */
+ s_ibuf->rect = 0;
+
+ IMB_freeImBuf(s_ibuf);
+ }
+ }
+ }
+
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
+ if (proxy_sizes_in_use & proxy_sizes[i]) {
+ AVI_close_compress (proxy_ctx[i]);
+ MEM_freeN (proxy_ctx[i]);
+
+ get_proxy_filename(anim, proxy_sizes[i],
+ fname_tmp, TRUE);
+ get_proxy_filename(anim, proxy_sizes[i],
+ fname, FALSE);
+
+ if (*stop) {
+ unlink(fname_tmp);
+ } else {
+ rename(fname_tmp, fname);
+ }
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------
+ - public API
+ ---------------------------------------------------------------------- */
+
+void IMB_anim_index_rebuild(struct anim * anim, IMB_Timecode_Type tcs_in_use,
+ IMB_Proxy_Size proxy_sizes_in_use,
+ int quality,
+ short *stop, short *do_update, float *progress)
+{
+ switch (anim->curtype) {
+#ifdef WITH_FFMPEG
+ case ANIM_FFMPEG:
+ index_rebuild_ffmpeg(anim, tcs_in_use, proxy_sizes_in_use,
+ quality, stop, do_update, progress);
+ break;
+#endif
+ default:
+ index_rebuild_fallback(anim, tcs_in_use, proxy_sizes_in_use,
+ quality, stop, do_update, progress);
+ break;
+ }
+}
+
+void IMB_free_indices(struct anim * anim)
+{
+ int i;
+
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
+ if (anim->proxy_anim[i]) {
+ IMB_close_anim(anim->proxy_anim[i]);
+ anim->proxy_anim[i] = 0;
+ }
+ }
+
+ for (i = 0; i < IMB_TC_MAX_SLOT; i++) {
+ if (anim->curr_idx[i]) {
+ IMB_indexer_close(anim->curr_idx[i]);
+ anim->curr_idx[i] = 0;
+ }
+ }
+
+
+ anim->proxies_tried = 0;
+ anim->indices_tried = 0;
+}
+
+void IMB_anim_set_index_dir(struct anim * anim, const char * dir)
+{
+ if (strcmp(anim->index_dir, dir) == 0) {
+ return;
+ }
+ BLI_strncpy(anim->index_dir, dir, sizeof(anim->index_dir));
+
+ IMB_free_indices(anim);
+}
+
+struct anim * IMB_anim_open_proxy(
+ struct anim * anim, IMB_Proxy_Size preview_size)
+{
+ char fname[FILE_MAXDIR+FILE_MAXFILE];
+ int i = IMB_proxy_size_to_array_index(preview_size);
+
+ if (anim->proxy_anim[i]) {
+ return anim->proxy_anim[i];
+ }
+
+ if (anim->proxies_tried & preview_size) {
+ return NULL;
+ }
+
+ get_proxy_filename(anim, preview_size, fname, FALSE);
+
+ anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0);
+
+ anim->proxies_tried |= preview_size;
+
+ return anim->proxy_anim[i];
+}
+
+struct anim_index * IMB_anim_open_index(
+ struct anim * anim, IMB_Timecode_Type tc)
+{
+ char fname[FILE_MAXDIR+FILE_MAXFILE];
+ int i = IMB_timecode_to_array_index(tc);
+
+ if (anim->curr_idx[i]) {
+ return anim->curr_idx[i];
+ }
+
+ if (anim->indices_tried & tc) {
+ return 0;
+ }
+
+ get_tc_filename(anim, tc, fname);
+
+ anim->curr_idx[i] = IMB_indexer_open(fname);
+
+ anim->indices_tried |= tc;
+
+ return anim->curr_idx[i];
+}
+
+int IMB_anim_index_get_frame_index(struct anim * anim, IMB_Timecode_Type tc,
+ int position)
+{
+ struct anim_index * idx = IMB_anim_open_index(anim, tc);
+
+ if (!idx) {
+ return position;
+ }
+
+ return IMB_indexer_get_frame_index(idx, position);
+}
+
diff --git a/source/blender/imbuf/intern/indexer_dv.c b/source/blender/imbuf/intern/indexer_dv.c
new file mode 100644
index 00000000000..0961af10f69
--- /dev/null
+++ b/source/blender/imbuf/intern/indexer_dv.c
@@ -0,0 +1,391 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Peter Schlaile <peter [at] schlaile [dot] de> 2011
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "IMB_indexer.h"
+#include "MEM_guardedalloc.h"
+#include <time.h>
+
+typedef struct indexer_dv_bitstream {
+ unsigned char* buffer;
+ int bit_pos;
+} indexer_dv_bitstream;
+
+static indexer_dv_bitstream bitstream_new(unsigned char* buffer_)
+{
+ indexer_dv_bitstream rv;
+
+ rv.buffer = buffer_;
+ rv.bit_pos = 0;
+
+ return rv;
+}
+
+static unsigned long bitstream_get_bits(indexer_dv_bitstream * This, int num)
+{
+ int byte_pos = This->bit_pos >> 3;
+ unsigned long i =
+ This->buffer[byte_pos] | (This->buffer[byte_pos + 1] << 8) |
+ (This->buffer[byte_pos + 2] << 16) |
+ (This->buffer[byte_pos + 3] << 24);
+ int rval = (i >> (This->bit_pos & 0x7)) & ((1 << num) - 1);
+ This->bit_pos += num;
+ return rval;
+}
+
+static int parse_num(indexer_dv_bitstream * b, int numbits) {
+ return bitstream_get_bits(b, numbits);
+}
+
+static int parse_bcd(indexer_dv_bitstream * b, int n)
+{
+ char s[256];
+ char * p = s + (n+3)/4;
+
+ *p-- = 0;
+
+ while (n > 4) {
+ char a;
+ int v = bitstream_get_bits(b, 4);
+
+ n -= 4;
+ a = '0' + v;
+
+ if (a > '9') {
+ bitstream_get_bits(b, n);
+ return -1;
+ }
+
+ *p-- = a;
+ }
+ if (n) {
+ char a;
+ int v = bitstream_get_bits(b, n);
+ a = '0' + v;
+ if (a > '9') {
+ return -1;
+ }
+ *p-- = a;
+ }
+
+ return atol(s);
+}
+
+typedef struct indexer_dv_context
+{
+ int rec_curr_frame;
+ int rec_curr_second;
+ int rec_curr_minute;
+ int rec_curr_hour;
+
+ int rec_curr_day;
+ int rec_curr_month;
+ int rec_curr_year;
+
+ char got_record_date;
+ char got_record_time;
+
+ time_t ref_time_read;
+ time_t ref_time_read_new;
+ int curr_frame;
+
+ time_t gap_start;
+ int gap_frame;
+
+ int frameno_offset;
+
+ anim_index_entry backbuffer[31];
+ int fsize;
+
+ anim_index_builder * idx;
+} indexer_dv_context;
+
+static void parse_packet(indexer_dv_context * This, unsigned char * p)
+{
+ indexer_dv_bitstream b;
+ int type = p[0];
+
+ b = bitstream_new(p + 1);
+
+ switch (type) {
+ case 0x62: // Record date
+ parse_num(&b, 8);
+ This->rec_curr_day = parse_bcd(&b, 6);
+ parse_num(&b, 2);
+ This->rec_curr_month = parse_bcd(&b, 5);
+ parse_num(&b, 3);
+ This->rec_curr_year = parse_bcd(&b, 8);
+ if (This->rec_curr_year < 25) {
+ This->rec_curr_year += 2000;
+ } else {
+ This->rec_curr_year += 1900;
+ }
+ This->got_record_date = 1;
+ break;
+ case 0x63: // Record time
+ This->rec_curr_frame = parse_bcd(&b, 6);
+ parse_num(&b, 2);
+ This->rec_curr_second = parse_bcd(&b, 7);
+ parse_num(&b, 1);
+ This->rec_curr_minute = parse_bcd(&b, 7);
+ parse_num(&b, 1);
+ This->rec_curr_hour = parse_bcd(&b, 6);
+ This->got_record_time = 1;
+ break;
+ }
+}
+
+static void parse_header_block(indexer_dv_context * This, unsigned char* target)
+{
+ int i;
+ for (i = 3; i < 80; i += 5) {
+ if (target[i] != 0xff) {
+ parse_packet(This, target + i);
+ }
+ }
+}
+
+static void parse_subcode_blocks(
+ indexer_dv_context * This, unsigned char* target)
+{
+ int i,j;
+
+ for (j = 0; j < 2; j++) {
+ for (i = 3; i < 80; i += 5) {
+ if (target[i] != 0xff) {
+ parse_packet(This, target + i);
+ }
+ }
+ }
+}
+
+static void parse_vaux_blocks(
+ indexer_dv_context * This, unsigned char* target)
+{
+ int i,j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 3; i < 80; i += 5) {
+ if (target[i] != 0xff) {
+ parse_packet(This, target + i);
+ }
+ }
+ target += 80;
+ }
+}
+
+static void parse_audio_headers(
+ indexer_dv_context * This, unsigned char* target)
+{
+ int i;
+
+ for(i = 0; i < 9; i++) {
+ if (target[3] != 0xff) {
+ parse_packet(This, target + 3);
+ }
+ target += 16 * 80;
+ }
+}
+
+static void parse_frame(indexer_dv_context * This,
+ unsigned char * framebuffer, int isPAL)
+{
+ int numDIFseq = isPAL ? 12 : 10;
+ unsigned char* target = framebuffer;
+ int ds;
+
+ for (ds = 0; ds < numDIFseq; ds++) {
+ parse_header_block(This, target);
+ target += 1 * 80;
+ parse_subcode_blocks(This, target);
+ target += 2 * 80;
+ parse_vaux_blocks(This, target);
+ target += 3 * 80;
+ parse_audio_headers(This, target);
+ target += 144 * 80;
+ }
+}
+
+static void inc_frame(int * frame, time_t * t, int isPAL)
+{
+ if ((isPAL && *frame >= 25) || (!isPAL && *frame >= 30)) {
+ fprintf(stderr, "Ouchie: inc_frame: invalid_frameno: %d\n",
+ *frame);
+ }
+ (*frame)++;
+ if (isPAL && *frame >= 25) {
+ (*t)++;
+ *frame = 0;
+ } else if (!isPAL && *frame >= 30) {
+ (*t)++;
+ *frame = 0;
+ }
+}
+
+static void write_index(indexer_dv_context * This, anim_index_entry * entry)
+{
+ IMB_index_builder_add_entry(
+ This->idx, entry->frameno + This->frameno_offset,
+ entry->seek_pos, entry->seek_pos_dts, entry->pts);
+}
+
+static void fill_gap(indexer_dv_context * This, int isPAL)
+{
+ int i;
+
+ for (i = 0; i < This->fsize; i++) {
+ if (This->gap_start == This->ref_time_read &&
+ This->gap_frame == This->curr_frame) {
+ fprintf(stderr,
+ "indexer_dv::fill_gap: "
+ "can't seek backwards !\n");
+ break;
+ }
+ inc_frame(&This->gap_frame, &This->gap_start, isPAL);
+ }
+
+ while (This->gap_start != This->ref_time_read ||
+ This->gap_frame != This->curr_frame) {
+ inc_frame(&This->gap_frame, &This->gap_start, isPAL);
+ This->frameno_offset++;
+ }
+
+ for (i = 0; i < This->fsize; i++) {
+ write_index(This, This->backbuffer + i);
+ }
+ This->fsize = 0;
+}
+
+static void proc_frame(indexer_dv_context * This,
+ unsigned char* framebuffer, int isPAL)
+{
+ struct tm recDate;
+ time_t t;
+
+ if (!This->got_record_date || !This->got_record_time) {
+ return;
+ }
+
+ recDate.tm_sec = This->rec_curr_second;
+ recDate.tm_min = This->rec_curr_minute;
+ recDate.tm_hour = This->rec_curr_hour;
+ recDate.tm_mday = This->rec_curr_day;
+ recDate.tm_mon = This->rec_curr_month - 1;
+ recDate.tm_year = This->rec_curr_year - 1900;
+ recDate.tm_wday = -1;
+ recDate.tm_yday = -1;
+ recDate.tm_isdst = -1;
+
+ t = mktime(&recDate);
+ if (t == -1) {
+ return;
+ }
+
+ This->ref_time_read_new = t;
+
+ if (This->ref_time_read < 0) {
+ This->ref_time_read = This->ref_time_read_new;
+ This->curr_frame = 0;
+ } else {
+ if (This->ref_time_read_new - This->ref_time_read == 1) {
+ This->curr_frame = 0;
+ This->ref_time_read = This->ref_time_read_new;
+ if (This->gap_frame >= 0) {
+ fill_gap(This, isPAL);
+ This->gap_frame = -1;
+ }
+ } else if (This->ref_time_read_new == This->ref_time_read) {
+ // do nothing
+ } else {
+ This->gap_start = This->ref_time_read;
+ This->gap_frame = This->curr_frame;
+ This->ref_time_read = This->ref_time_read_new;
+ This->curr_frame = -1;
+ }
+ }
+}
+
+static void indexer_dv_proc_frame(anim_index_builder * idx,
+ unsigned char * buffer,
+ int data_size,
+ struct anim_index_entry * entry)
+{
+ int isPAL;
+
+ indexer_dv_context * This = (indexer_dv_context *) idx->private_data;
+
+ isPAL = (buffer[3] & 0x80);
+
+ This->got_record_date = FALSE;
+ This->got_record_time = FALSE;
+
+ parse_frame(This, buffer, isPAL);
+ proc_frame(This, buffer, isPAL);
+
+ if (This->curr_frame >= 0) {
+ write_index(This, entry);
+ inc_frame(&This->curr_frame, &This->ref_time_read, isPAL);
+ } else {
+ This->backbuffer[This->fsize++] = *entry;
+ if (This->fsize >= 31) {
+ int i;
+
+ fprintf(stderr, "indexer_dv::indexer_dv_proc_frame: "
+ "backbuffer overrun, emergency flush");
+
+ for (i = 0; i < This->fsize; i++) {
+ write_index(This, This->backbuffer+i);
+ }
+ This->fsize = 0;
+ }
+ }
+}
+
+static void indexer_dv_delete(anim_index_builder * idx)
+{
+ int i = 0;
+ indexer_dv_context * This = (indexer_dv_context *) idx->private_data;
+
+ for (i = 0; i < This->fsize; i++) {
+ write_index(This, This->backbuffer+i);
+ }
+
+ MEM_freeN(This);
+}
+
+void IMB_indexer_dv_new(anim_index_builder * idx)
+{
+ indexer_dv_context * rv = MEM_callocN(
+ sizeof(indexer_dv_context), "index_dv builder context");
+
+ rv->ref_time_read = -1;
+ rv->curr_frame = -1;
+ rv->gap_frame = -1;
+ rv->idx = idx;
+
+ idx->private_data = rv;
+ idx->proc_frame = indexer_dv_proc_frame;
+ idx->delete_priv_data = indexer_dv_delete;
+}
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 1d91f34f4fa..2ab7e55d1f8 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -317,9 +317,9 @@ ImBuf* IMB_thumb_create(const char* path, ThumbSize size, ThumbSource source, Im
}
} else if (THB_SOURCE_MOVIE == source) {
struct anim * anim = NULL;
- anim = IMB_open_anim(path, IB_rect | IB_metadata);
+ anim = IMB_open_anim(path, IB_rect | IB_metadata, 0);
if (anim != NULL) {
- img = IMB_anim_absolute(anim, 0);
+ img = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (img == NULL) {
printf("not an anim; %s\n", path);
} else {
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 36130aa0dbf..7beb853fe62 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -646,7 +646,7 @@ void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, size_t size, int tx, int
}
}
else
- printf("imb_loadtiff: mipmap level %d has unexpected size %dx%d instead of %dx%d\n", ibuf->miplevel, width, height, ibuf->x, ibuf->y);
+ printf("imb_loadtiff: mipmap level %d has unexpected size %ux%u instead of %dx%d\n", ibuf->miplevel, width, height, ibuf->x, ibuf->y);
}
else
printf("imb_loadtiff: could not find mipmap level %d\n", ibuf->miplevel);
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 6db8dcc06cf..85d31f18a03 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -221,7 +221,7 @@ void silence_log_ffmpeg(int quiet)
}
else
{
- av_log_set_level(AV_LOG_INFO);
+ av_log_set_level(AV_LOG_DEBUG);
}
}
@@ -234,9 +234,10 @@ void do_init_ffmpeg(void)
av_register_all();
avdevice_register_all();
- if ((G.f & G_DEBUG) == 0)
- {
+ if ((G.f & G_DEBUG) == 0) {
silence_log_ffmpeg(1);
+ } else {
+ silence_log_ffmpeg(0);
}
}
}