Camera tracking integration

===========================

Commiting VSE-proxies patch from Peter Schlaile.

Description is here: http://lists.blender.org/pipermail/bf-committers/2011-May/032152.html
Git commit hash: baaecf244b83c70cb57e1bf6fdd51dd8591bde5b
This commit is contained in:
Sergey Sharybin 2011-08-08 12:18:20 +00:00
parent 14e7aa25de
commit 33e829819e
33 changed files with 2597 additions and 316 deletions

@ -694,11 +694,11 @@ elseif(WIN32)
${LIBDIR}/ffmpeg/include/msvc
)
set(FFMPEG_LIBRARIES
${LIBDIR}/ffmpeg/lib/avcodec-52.lib
${LIBDIR}/ffmpeg/lib/avformat-52.lib
${LIBDIR}/ffmpeg/lib/avdevice-52.lib
${LIBDIR}/ffmpeg/lib/avutil-50.lib
${LIBDIR}/ffmpeg/lib/swscale-0.lib
${LIBDIR}/ffmpeg/lib/avcodec-53.lib
${LIBDIR}/ffmpeg/lib/avformat-53.lib
${LIBDIR}/ffmpeg/lib/avdevice-53.lib
${LIBDIR}/ffmpeg/lib/avutil-51.lib
${LIBDIR}/ffmpeg/lib/swscale-2.lib
)
endif()
@ -825,7 +825,7 @@ elseif(WIN32)
if(WITH_CODEC_FFMPEG)
set(FFMPEG ${LIBDIR}/ffmpeg)
set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include ${FFMPEG}/include)
set(FFMPEG_LIBRARIES avcodec-52 avformat-52 avdevice-52 avutil-50 swscale-0)
set(FFMPEG_LIBRARIES avcodec-53 avformat-53 avdevice-53 avutil-51 swscale-2)
set(FFMPEG_LIBPATH ${FFMPEG}/lib)
endif()

@ -98,7 +98,7 @@ else:
# enable ffmpeg support
WITH_BF_FFMPEG = True # -DWITH_FFMPEG
BF_FFMPEG = LIBDIR + '/ffmpeg'
BF_FFMPEG = LIBDIR + '/ffmpeg-9.8'
BF_FFMPEG_INC = "${BF_FFMPEG}/include"
BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
BF_FFMPEG_LIB = 'avcodec avdevice avformat avutil mp3lame swscale x264 xvidcore theora theoradec theoraenc vorbis vorbisenc vorbisfile ogg bz2'

@ -125,8 +125,9 @@ WITH_BF_BINRELOC = False
# enable ffmpeg support
WITH_BF_FFMPEG = True # -DWITH_FFMPEG
BF_FFMPEG = LIBDIR + '/ffmpeg'
BF_FFMPEG_LIB = 'avformat-52 avcodec-52 avdevice-52 avutil-50 swscale-0'
BF_FFMPEG = LIBDIR + '/ffmpeg-0.8'
BF_FFMPEG_LIB = 'avformat-53 avcodec-53 avdevice-53 avutil-51 swscale-2'
BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-53.dll ${BF_FFMPEG_LIBPATH}/avcodec-53.dll ${BF_FFMPEG_LIBPATH}/avdevice-53.dll ${BF_FFMPEG_LIBPATH}/avutil-51.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll'
BF_FFMPEG_INC = '${BF_FFMPEG}/include'
BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib'

@ -18,9 +18,11 @@ BF_OPENAL_LIB = 'wrap_oal'
BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
WITH_BF_FFMPEG = False
BF_FFMPEG_LIB = 'avformat-52 avcodec-52 avdevice-52 avutil-50 swscale-0'
BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
BF_FFMPEG_LIB = 'avformat-53 avcodec-53 avdevice-53 avutil-51 swscale-2'
BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg-0.8/lib'
BF_FFMPEG_INC = LIBDIR + '/ffmpeg-0.8/include'
BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-53.dll ${BF_FFMPEG_LIBPATH}/avcodec-53.dll ${BF_FFMPEG_LIBPATH}/avdevice-53.dll ${BF_FFMPEG_LIBPATH}/avutil-51.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll'
BF_LIBSAMPLERATE = LIBDIR + '/samplerate'
BF_LIBSAMPLERATE_INC = '${BF_LIBSAMPLERATE}/include'

@ -3,11 +3,11 @@ LIBDIR = '${LCGDIR}'
# enable ffmpeg support
WITH_BF_FFMPEG = True # -DWITH_FFMPEG
BF_FFMPEG = LIBDIR +'/ffmpeg'
BF_FFMPEG = LIBDIR +'/ffmpeg-0.8'
BF_FFMPEG_INC = '${BF_FFMPEG}/include ${BF_FFMPEG}/include/msvc'
BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
BF_FFMPEG_LIB = 'avformat-52.lib avcodec-52.lib avdevice-52.lib avutil-50.lib swscale-0.lib'
BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-52.dll ${BF_FFMPEG_LIBPATH}/avcodec-52.dll ${BF_FFMPEG_LIBPATH}/avdevice-52.dll ${BF_FFMPEG_LIBPATH}/avutil-50.dll ${BF_FFMPEG_LIBPATH}/swscale-0.dll'
BF_FFMPEG_LIB = 'avformat-53.lib avcodec-53.lib avdevice-53.lib avutil-51.lib swscale-2.lib'
BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-53.dll ${BF_FFMPEG_LIBPATH}/avcodec-53.dll ${BF_FFMPEG_LIBPATH}/avdevice-53.dll ${BF_FFMPEG_LIBPATH}/avutil-51.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll'
BF_PYTHON = LIBDIR + '/python'
BF_PYTHON_VERSION = '3.2'

@ -3,11 +3,11 @@ LIBDIR = '${LCGDIR}'
# enable ffmpeg support
WITH_BF_FFMPEG = True # -DWITH_FFMPEG
BF_FFMPEG = LIBDIR +'/ffmpeg'
BF_FFMPEG = LIBDIR +'/ffmpeg-0.8'
BF_FFMPEG_INC = '${BF_FFMPEG}/include ${BF_FFMPEG}/include/msvc '
BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
BF_FFMPEG_LIB = 'avformat-52.lib avcodec-52.lib avdevice-52.lib avutil-50.lib swscale-0.lib'
BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-52.dll ${BF_FFMPEG_LIBPATH}/avcodec-52.dll ${BF_FFMPEG_LIBPATH}/avdevice-52.dll ${BF_FFMPEG_LIBPATH}/avutil-50.dll ${BF_FFMPEG_LIBPATH}/swscale-0.dll'
BF_FFMPEG_LIB = 'avformat-53.lib avcodec-53.lib avdevice-53.lib avutil-51.lib swscale-2.lib'
BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-53.dll ${BF_FFMPEG_LIBPATH}/avcodec-53.dll ${BF_FFMPEG_LIBPATH}/avdevice-53.dll ${BF_FFMPEG_LIBPATH}/avutil-51.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll'
BF_PYTHON = LIBDIR + '/python'
BF_PYTHON_VERSION = '3.2'

@ -71,6 +71,7 @@
#define avio_open url_fopen
#define avio_tell url_ftell
#define avio_close url_fclose
#define avio_size url_fsize
#endif
/* there are some version inbetween, which have avio_... functions but no
@ -130,4 +131,19 @@ int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
}
#endif
static inline
int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame * picture)
{
int64_t pts = picture->pkt_pts;
if (pts == AV_NOPTS_VALUE) {
pts = picture->pkt_dts;
}
if (pts == AV_NOPTS_VALUE) {
pts = 0;
}
return pts;
}
#endif

@ -60,6 +60,7 @@ class SEQUENCER_HT_header(bpy.types.Header):
layout.separator()
layout.operator("sequencer.refresh_all")
layout.template_running_jobs()
elif st.view_type == 'SEQUENCER_PREVIEW':
layout.separator()
layout.operator("sequencer.refresh_all")
@ -234,6 +235,7 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
layout.operator("sequencer.cut", text="Cut (soft) at frame").type = 'SOFT'
layout.operator("sequencer.images_separate")
layout.operator("sequencer.deinterlace_selected_movies")
layout.operator("sequencer.rebuild_proxy")
layout.separator()
layout.operator("sequencer.duplicate")
@ -733,7 +735,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, bpy.types.Panel):
class SEQUENCER_PT_proxy(SequencerButtonsPanel, bpy.types.Panel):
bl_label = "Proxy"
bl_label = "Proxy / Timecode"
@classmethod
def poll(cls, context):
@ -759,12 +761,29 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, bpy.types.Panel):
flow = layout.column_flow()
flow.prop(strip, "use_proxy_custom_directory")
flow.prop(strip, "use_proxy_custom_file")
if strip.proxy: # TODO - need to add this somehow
if strip.proxy:
if strip.use_proxy_custom_directory and not strip.use_proxy_custom_file:
flow.prop(strip.proxy, "directory")
if strip.use_proxy_custom_file:
flow.prop(strip.proxy, "filepath")
row = layout.row()
row.label(text="Build Sizes:")
row.prop(strip.proxy, "build_25")
row.prop(strip.proxy, "build_50")
row.prop(strip.proxy, "build_75")
col = layout.column()
col.label(text="Build JPEG quality")
col.prop(strip.proxy, "quality")
if strip.type == "MOVIE":
col = layout.column()
col.label(text="Use timecode index:")
col.prop(strip.proxy, "timecode")
class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, bpy.types.Panel):
bl_label = "Scene Preview/Render"

@ -177,6 +177,7 @@ int seq_recursive_apply(struct Sequence *seq, int (*apply_func)(struct Sequence
/* maintainance functions, mostly for RNA */
// extern
void seq_free_sequence(struct Scene *scene, struct Sequence *seq);
void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq);
void seq_free_strip(struct Strip *strip);
void seq_free_editing(struct Scene *scene);
void seq_free_clipboard(void);
@ -199,6 +200,11 @@ void update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_s
int input_have_to_preprocess(
SeqRenderData context, struct Sequence * seq, float cfra);
void seq_proxy_rebuild(struct Main * bmain,
struct Scene *scene, struct Sequence * seq,
short *stop, short *do_update, float *progress);
/* **********************************************************************
seqcache.c

@ -1379,7 +1379,7 @@ struct anim *openanim(char *name, int flags)
anim = IMB_open_anim(name, flags);
if (anim == NULL) return NULL;
ibuf = IMB_anim_absolute(anim, 0);
ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (ibuf == NULL) {
if(BLI_exists(name))
printf("not an anim: %s\n", name);
@ -1777,16 +1777,21 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
/* let's initialize this user */
if(ima->anim && iuser && iuser->frames==0)
iuser->frames= IMB_anim_get_duration(ima->anim);
iuser->frames= IMB_anim_get_duration(ima->anim,
IMB_TC_RECORD_RUN);
}
if(ima->anim) {
int dur = IMB_anim_get_duration(ima->anim);
int dur = IMB_anim_get_duration(ima->anim,
IMB_TC_RECORD_RUN);
int fra= frame-1;
if(fra<0) fra = 0;
if(fra>(dur-1)) fra= dur-1;
ibuf = IMB_anim_absolute(ima->anim, fra);
ibuf = IMB_makeSingleUser(
IMB_anim_absolute(ima->anim, fra,
IMB_TC_RECORD_RUN,
IMB_PROXY_NONE));
if(ibuf) {
image_initialize_after_load(ima, ibuf);

@ -134,7 +134,7 @@ static ImBuf *movieclip_load_movie_file(MovieClip *clip, int framenr)
}
if(clip->anim) {
int dur= IMB_anim_get_duration(clip->anim);
int dur= IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
int fra= framenr-1;
if(fra<0)
@ -143,7 +143,7 @@ static ImBuf *movieclip_load_movie_file(MovieClip *clip, int framenr)
if(fra>(dur-1))
fra= dur-1;
ibuf= IMB_anim_absolute(clip->anim, fra);
ibuf= IMB_anim_absolute(clip->anim, fra, IMB_TC_NONE, IMB_PROXY_NONE);
}
return ibuf;

@ -218,6 +218,18 @@ void seq_free_sequence(Scene *scene, Sequence *seq)
MEM_freeN(seq);
}
void seq_free_sequence_recurse(Scene *scene, Sequence *seq)
{
Sequence *iseq;
for(iseq= seq->seqbase.first; iseq; iseq= iseq->next) {
seq_free_sequence_recurse(scene, iseq);
}
seq_free_sequence(scene, seq);
}
Editing *seq_give_editing(Scene *scene, int alloc)
{
if (scene->ed == NULL && alloc) {
@ -689,7 +701,10 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq, int lock_range)
return;
}
seq->len = IMB_anim_get_duration(seq->anim);
seq->len = IMB_anim_get_duration(seq->anim,
seq->strip->proxy ?
seq->strip->proxy->tc :
IMB_TC_RECORD_RUN);
seq->anim_preseek = IMB_anim_get_preseek(seq->anim);
@ -1124,6 +1139,53 @@ static int get_shown_sequences( ListBase * seqbasep, int cfra, int chanshown, Se
#define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE)
static IMB_Proxy_Size seq_rendersize_to_proxysize(int size)
{
if (size >= 100) {
return IMB_PROXY_NONE;
}
if (size >= 75) {
return IMB_PROXY_75;
}
if (size >= 50) {
return IMB_PROXY_50;
}
return IMB_PROXY_25;
}
static void seq_open_anim_file(Sequence * seq)
{
char name[FILE_MAXDIR+FILE_MAXFILE];
StripProxy * proxy;
if(seq->anim != NULL) {
return;
}
BLI_join_dirfile(name, sizeof(name),
seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, G.main->name);
seq->anim = openanim(name, IB_rect |
((seq->flag & SEQ_FILTERY) ?
IB_animdeinterlace : 0));
if (seq->anim == NULL) {
return;
}
proxy = seq->strip->proxy;
if (proxy == NULL) {
return;
}
if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) {
IMB_anim_set_index_dir(seq->anim, seq->strip->proxy->dir);
}
}
static int seq_proxy_get_fname(SeqRenderData context, Sequence * seq, int cfra, char * name)
{
int frameno;
@ -1133,18 +1195,25 @@ static int seq_proxy_get_fname(SeqRenderData context, Sequence * seq, int cfra,
return FALSE;
}
/* MOVIE tracks (only exception: custom files) are now handled
internally by ImBuf module for various reasons: proper time code
support, quicker index build, using one file instead
of a full directory of jpeg files, etc. Trying to support old
and new method at once could lead to funny effects, if people
have both, a directory full of jpeg files and proxy avis, so
sorry folks, please rebuild your proxies... */
if (seq->flag & (SEQ_USE_PROXY_CUSTOM_DIR|SEQ_USE_PROXY_CUSTOM_FILE)) {
strcpy(dir, seq->strip->proxy->dir);
} else if (seq->type == SEQ_IMAGE) {
snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
} else {
if (ELEM(seq->type, SEQ_IMAGE, SEQ_MOVIE)) {
snprintf(dir, FILE_MAXDIR, "%s/BL_proxy", seq->strip->dir);
} else {
return FALSE;
}
return FALSE;
}
if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
BLI_join_dirfile(name, FILE_MAX, dir, seq->strip->proxy->file); /* XXX, not real length */
BLI_join_dirfile(name, PROXY_MAXFILE,
dir, seq->strip->proxy->file);
BLI_path_abs(name, G.main->name);
return TRUE;
@ -1152,20 +1221,14 @@ static int seq_proxy_get_fname(SeqRenderData context, Sequence * seq, int cfra,
/* generate a separate proxy directory for each preview size */
switch(seq->type) {
case SEQ_IMAGE:
if (seq->type == SEQ_IMAGE) {
snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir,
context.preview_render_size,
give_stripelem(seq, cfra)->name);
frameno = 1;
break;
case SEQ_MOVIE:
frameno = (int) give_stripelem_index(seq, cfra) + seq->anim_startofs;
snprintf(name, PROXY_MAXFILE, "%s/%s/%d/####", dir,
seq->strip->stripdata->name, context.preview_render_size);
break;
default:
frameno = (int) give_stripelem_index(seq, cfra) + seq->anim_startofs;
} else {
frameno = (int) give_stripelem_index(seq, cfra)
+ seq->anim_startofs;
snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir,
context.preview_render_size);
}
@ -1204,7 +1267,13 @@ static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int
return NULL;
}
return IMB_anim_absolute(seq->strip->proxy->anim, frameno);
seq_open_anim_file(seq);
frameno = IMB_anim_index_get_frame_index(
seq->anim, seq->strip->proxy->tc, frameno);
return IMB_anim_absolute(seq->strip->proxy->anim, frameno,
IMB_TC_NONE, IMB_PROXY_NONE);
}
if (seq_proxy_get_fname(context, seq, cfra, name) == 0) {
@ -1218,58 +1287,24 @@ static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int
}
}
#if 0
static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra,
int build_proxy_run, int preview_render_size);
static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int preview_render_size, int seqrectx, int seqrecty)
static void seq_proxy_build_frame(SeqRenderData context,
Sequence* seq, int cfra,
int proxy_render_size)
{
char name[PROXY_MAXFILE];
int quality;
TStripElem * se;
int ok;
int rectx, recty;
int ok;
struct ImBuf * ibuf;
if (!(seq->flag & SEQ_USE_PROXY)) {
if (!seq_proxy_get_fname(context, seq, cfra, name)) {
return;
}
/* rendering at 100% ? No real sense in proxy-ing, right? */
if (preview_render_size == 100) {
return;
}
ibuf = seq_render_strip(context, seq, cfra);
/* that's why it is called custom... */
if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
return;
}
if (!seq_proxy_get_fname(scene, seq, cfra, name, preview_render_size)) {
return;
}
se = give_tstripelem(seq, cfra);
if (!se) {
return;
}
if(se->ibuf) {
IMB_freeImBuf(se->ibuf);
se->ibuf = 0;
}
do_build_seq_ibuf(scene, seq, se, cfra, TRUE, preview_render_size,
seqrectx, seqrecty);
if (!se->ibuf) {
return;
}
rectx= (preview_render_size*scene->r.xsch)/100;
recty= (preview_render_size*scene->r.ysch)/100;
ibuf = se->ibuf;
rectx = (proxy_render_size * context.scene->r.xsch) / 100;
recty = (proxy_render_size * context.scene->r.ysch) / 100;
if (ibuf->x != rectx || ibuf->y != recty) {
IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
@ -1291,69 +1326,76 @@ static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int pr
}
IMB_freeImBuf(ibuf);
se->ibuf = 0;
}
static void seq_proxy_rebuild(Scene *scene, Sequence * seq, int seqrectx,
int seqrecty)
void seq_proxy_rebuild(struct Main * bmain, Scene *scene, Sequence * seq,
short *stop, short *do_update, float *progress)
{
SeqRenderData context;
int cfra;
float rsize = seq->strip->proxy->size;
int tc_flags;
int size_flags;
int quality;
waitcursor(1);
G.afbreek = 0;
/* flag management tries to account for strobe and
other "non-linearities", that might come in the future...
better way would be to "touch" the files, so that _really_
no one is rebuild twice.
*/
for (cfra = seq->startdisp; cfra < seq->enddisp; cfra++) {
TStripElem * tse = give_tstripelem(seq, cfra);
tse->flag &= ~STRIPELEM_PREVIEW_DONE;
if (!seq->strip || !seq->strip->proxy) {
return;
}
/* a _lot_ faster for movie files, if we read frames in
sequential order */
if (seq->flag & SEQ_REVERSE_FRAMES) {
for (cfra = seq->enddisp-seq->endstill-1;
cfra >= seq->startdisp + seq->startstill; cfra--) {
TStripElem * tse = give_tstripelem(seq, cfra);
if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) {
//XXX set_timecursor(cfra);
seq_proxy_build_frame(scene, seq, cfra, rsize,
seqrectx, seqrecty);
tse->flag |= STRIPELEM_PREVIEW_DONE;
}
if (blender_test_break()) {
break;
}
}
} else {
for (cfra = seq->startdisp + seq->startstill;
cfra < seq->enddisp - seq->endstill; cfra++) {
TStripElem * tse = give_tstripelem(seq, cfra);
if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) {
//XXX set_timecursor(cfra);
seq_proxy_build_frame(scene, seq, cfra, rsize,
seqrectx, seqrecty);
tse->flag |= STRIPELEM_PREVIEW_DONE;
}
if (blender_test_break()) {
break;
}
}
if (!(seq->flag & SEQ_USE_PROXY)) {
return;
}
tc_flags = seq->strip->proxy->build_tc_flags;
size_flags = seq->strip->proxy->build_size_flags;
quality = seq->strip->proxy->quality;
if (seq->type == SEQ_MOVIE) {
seq_open_anim_file(seq);
if (seq->anim) {
IMB_anim_index_rebuild(
seq->anim, tc_flags, size_flags, quality,
stop, do_update, progress);
}
return;
}
if (!(seq->flag & SEQ_USE_PROXY)) {
return;
}
/* that's why it is called custom... */
if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
return;
}
/* fail safe code */
context = seq_new_render_data(
bmain, scene,
(scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f,
(scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f,
100);
for (cfra = seq->startdisp + seq->startstill;
cfra < seq->enddisp - seq->endstill; cfra++) {
if (size_flags & IMB_PROXY_25) {
seq_proxy_build_frame(context, seq, cfra, 25);
}
if (size_flags & IMB_PROXY_50) {
seq_proxy_build_frame(context, seq, cfra, 50);
}
if (size_flags & IMB_PROXY_75) {
seq_proxy_build_frame(context, seq, cfra, 75);
}
*progress= (float)cfra/(seq->enddisp - seq->endstill - seq->startdisp + seq->startstill);
*do_update= 1;
if(*stop || G.afbreek)
break;
}
waitcursor(0);
}
#endif
/* **********************************************************************
@ -1570,6 +1612,8 @@ static ImBuf * input_preprocess(
{
float mul;
ibuf = IMB_makeSingleUser(ibuf);
if((seq->flag & SEQ_FILTERY) && seq->type != SEQ_MOVIE) {
IMB_filtery(ibuf);
}
@ -2095,17 +2139,20 @@ static ImBuf * seq_render_strip(SeqRenderData context, Sequence * seq, float cfr
}
case SEQ_MOVIE:
{
if(seq->anim==NULL) {
BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, G.main->name);
seq->anim = openanim(name, IB_rect |
((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0));
}
seq_open_anim_file(seq);
if(seq->anim) {
IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs);
IMB_anim_set_preseek(seq->anim,
seq->anim_preseek);
ibuf = IMB_anim_absolute(
seq->anim, nr + seq->anim_startofs,
seq->strip->proxy ?
seq->strip->proxy->tc
: IMB_TC_RECORD_RUN,
seq_rendersize_to_proxysize(
context.preview_render_size));
/* we don't need both (speed reasons)! */
if (ibuf && ibuf->rect_float && ibuf->rect)
imb_freerectImBuf(ibuf);
@ -3599,7 +3646,7 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
/* basic defaults */
seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
strip->len = seq->len = IMB_anim_get_duration( an );
strip->len = seq->len = IMB_anim_get_duration( an, IMB_TC_RECORD_RUN );
strip->us= 1;
/* we only need 1 element for MOVIE strips */

@ -10060,12 +10060,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
if(ed) {
SEQP_BEGIN(ed, seq) {
if (seq->strip && seq->strip->proxy){
if (sce->r.size != 100.0) {
seq->strip->proxy->size
= sce->r.size;
} else {
seq->strip->proxy->size = 25;
}
seq->strip->proxy->quality =90;
}
}

@ -2367,6 +2367,7 @@ void uiTemplateOperatorSearch(uiLayout *layout)
#define B_STOPANIM 3
#define B_STOPCOMPO 4
#define B_STOPCLIP 5
#define B_STOPSEQ 6
static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
{
@ -2386,6 +2387,9 @@ static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
case B_STOPCLIP:
WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
break;
case B_STOPSEQ:
WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
break;
}
}
@ -2412,8 +2416,11 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
if(WM_jobs_test(wm, sa))
owner = sa;
handle_event= B_STOPCLIP;
}
else {
} else if (sa->spacetype==SPACE_SEQ) {
if(WM_jobs_test(wm, sa))
owner = sa;
handle_event = B_STOPSEQ;
} else {
Scene *scene;
/* another scene can be rendering too, for example via compositor */
for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)

@ -113,7 +113,7 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
if(ima->source==IMA_SRC_MOVIE) {
ofs+= sprintf(str, "Movie");
if(ima->anim)
ofs+= sprintf(str+ofs, "%d frs", IMB_anim_get_duration(ima->anim));
ofs+= sprintf(str+ofs, "%d frs", IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
}
else
ofs+= sprintf(str, "Image");
@ -428,7 +428,7 @@ static void set_frames_cb(bContext *C, void *ima_v, void *iuser_v)
ImageUser *iuser= iuser_v;
if(ima->anim) {
iuser->frames = IMB_anim_get_duration(ima->anim);
iuser->frames = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
BKE_image_user_calc_frame(iuser, scene->r.cfra, 0);
}
}

@ -47,6 +47,7 @@
#include "BLI_math.h"
#include "BLI_storage_types.h"
#include "BLI_utildefines.h"
#include "BLI_threads.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
@ -129,6 +130,111 @@ typedef struct TransSeq {
int len;
} TransSeq;
/* ********************************************************************** */
/* ***************** proxy job manager ********************** */
typedef struct ProxyBuildJob {
Scene *scene;
struct Main * main;
ListBase queue;
ThreadMutex queue_lock;
} ProxyJob;
static void proxy_freejob(void *pjv)
{
ProxyJob *pj= pjv;
Sequence * seq;
for (seq = pj->queue.first; seq; seq = seq->next) {
BLI_remlink(&pj->queue, seq);
seq_free_sequence_recurse(pj->scene, seq);
}
BLI_mutex_end(&pj->queue_lock);
MEM_freeN(pj);
}
/* only this runs inside thread */
static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
{
ProxyJob *pj = pjv;
while (!*stop) {
Sequence * seq;
BLI_mutex_lock(&pj->queue_lock);
if (!pj->queue.first) {
BLI_mutex_unlock(&pj->queue_lock);
break;
}
seq = pj->queue.first;
BLI_remlink(&pj->queue, seq);
BLI_mutex_unlock(&pj->queue_lock);
seq_proxy_rebuild(pj->main, pj->scene, seq,
stop, do_update, progress);
seq_free_sequence_recurse(pj->scene, seq);
}
if (*stop) {
fprintf(stderr,
"Canceling proxy rebuild on users request...\n");
}
}
static void proxy_endjob(void *UNUSED(customdata))
{
}
void seq_proxy_build_job(const bContext *C, Sequence * seq)
{
wmJob * steve;
ProxyJob *pj;
Scene *scene= CTX_data_scene(C);
ScrArea * sa= CTX_wm_area(C);
seq = seq_dupli_recursive(scene, scene, seq, 0);
steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C),
sa, "Building Proxies", WM_JOB_PROGRESS);
pj = WM_jobs_get_customdata(steve);
if (!pj) {
pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
pj->scene= scene;
pj->main = CTX_data_main(C);
BLI_mutex_init(&pj->queue_lock);
WM_jobs_customdata(steve, pj, proxy_freejob);
WM_jobs_timer(steve, 0.1, NC_SCENE|ND_SEQUENCER,
NC_SCENE|ND_SEQUENCER);
WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL,
proxy_endjob);
}
BLI_mutex_lock(&pj->queue_lock);
BLI_addtail(&pj->queue, seq);
BLI_mutex_unlock(&pj->queue_lock);
if (!WM_jobs_is_running(steve)) {
G.afbreek = 0;
WM_jobs_start(CTX_wm_manager(C), steve);
}
ED_area_tag_redraw(CTX_wm_area(C));
}
/* ********************************************************************** */
void seq_rectf(Sequence *seq, rctf *rectf)
{
if(seq->startstill) rectf->xmin= seq->start;
@ -2830,3 +2936,35 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
/* rna */
WM_operator_properties_gesture_border(ot, FALSE);
}
/* rebuild_proxy operator */
static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Editing *ed = seq_give_editing(scene, FALSE);
Sequence * seq;
SEQP_BEGIN(ed, seq) {
if ((seq->flag & SELECT)) {
seq_proxy_build_job(C, seq);
}
}
SEQ_END
return OPERATOR_FINISHED;
}
void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Rebuild Proxy and Timecode Indices";
ot->idname= "SEQUENCER_OT_rebuild_proxy";
ot->description="Rebuild all selected proxies and timecode indeces using the job system";
/* api callbacks */
ot->exec= sequencer_rebuild_proxy_exec;
ot->poll= ED_operator_sequencer_active;
/* flags */
ot->flag= OPTYPE_REGISTER;
}

@ -111,6 +111,8 @@ void SEQUENCER_OT_view_ghost_border(struct wmOperatorType *ot);
void SEQUENCER_OT_copy(struct wmOperatorType *ot);
void SEQUENCER_OT_paste(struct wmOperatorType *ot);
void SEQUENCER_OT_rebuild_proxy(struct wmOperatorType *ot);
/* preview specific operators */
void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot);

@ -86,6 +86,8 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_view_zoom_ratio);
WM_operatortype_append(SEQUENCER_OT_view_ghost_border);
WM_operatortype_append(SEQUENCER_OT_rebuild_proxy);
/* sequencer_select.c */
WM_operatortype_append(SEQUENCER_OT_select_all_toggle);
WM_operatortype_append(SEQUENCER_OT_select_inverse);

@ -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

@ -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);
/**
*
@ -192,10 +193,61 @@ void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx,
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_MAX_SLOT = 3
} 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);
/**
*
@ -204,6 +256,7 @@ int IMB_anim_get_duration(struct anim *anim);
struct anim *IMB_open_anim(const char *name, int ib_flags);
void IMB_close_anim(struct anim *anim);
/**
*
* @attention Defined in anim.c
@ -218,7 +271,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 */);
/**
*
@ -227,12 +283,6 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, int position);
*/
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

@ -127,12 +127,15 @@
#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 */
@ -149,9 +152,6 @@ struct anim {
int interlacing;
int preseek;
/* data */
struct ImBuf * ibuf1, * ibuf2;
/* avi */
struct _AviMovie *avi;
@ -179,11 +179,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

@ -0,0 +1,135 @@
/**
* IMB_indexer.h
*
* $Id: IMB_indexer.h
*
* ***** 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

@ -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;

@ -57,6 +57,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#ifndef _WIN32
#include <dirent.h>
#else
@ -90,6 +91,7 @@
#include "IMB_allocimbuf.h"
#include "IMB_anim.h"
#include "IMB_indexer.h"
#ifdef WITH_FFMPEG
#include <libavformat/avformat.h>
@ -304,15 +306,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 +319,6 @@ void IMB_free_anim(struct anim * anim) {
return;
}
IMB_free_anim_ibuf(anim);
free_anim_movie(anim);
free_anim_avi(anim);
@ -339,6 +331,7 @@ void IMB_free_anim(struct anim * anim) {
#ifdef WITH_REDCODE
free_anim_redcode(anim);
#endif
IMB_free_indices(anim);
MEM_freeN(anim);
}
@ -496,7 +489,7 @@ 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);
@ -517,6 +510,8 @@ static int startffmpeg(struct anim * anim) {
AVCodec *pCodec;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
int frs_num;
double frs_den;
#ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
/* The following for color space determination */
@ -575,6 +570,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 +592,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 +679,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 +712,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,77 +800,304 @@ 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;
int64_t pts_to_search = 0;
int pos_found = 1;
int filter_y = 0;
int seek_by_bytes= 0;
int preseek_count = 0;
/* decode one video frame and load the next packet into anim->packet,
so that we can obtain next_pts and next undecoded pts */
if (anim == 0) return (0);
static int ffmpeg_decode_video_frame(struct anim * anim)
{
int frameFinished = 0;
int rval = 0;
ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
avpicture_fill((AVPicture*) anim->pFrameRGB,
(unsigned char*) ibuf->rect,
PIX_FMT_RGBA, anim->x, anim->y);
anim->next_undecoded_pts = -1;
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 (anim->next_packet.stream_index == anim->videoStream) {
av_log(anim->pFormatCtx, AV_LOG_DEBUG,
" DECODE: cached next packet\n");
if (frameFinished) {
anim->curposition++;
}
}
av_free_packet(&packet);
if (position == anim->curposition+1) {
break;
}
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;
}
}
/* 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
return FALSE;
}
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);
static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position,
IMB_Timecode_Type tc) {
int64_t pts_to_search = 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);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position);
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)
rint(((double) position) / pts_time_base / frame_rate);
if (st_time != AV_NOPTS_VALUE) {
pts_to_search += st_time / pts_time_base
/ AV_TIME_BASE;
}
}
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");
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 *= anim->pFormatCtx->bit_rate / frame_rate;
pos /= 8;
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);
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;
@ -855,69 +1108,51 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
if (st_time != AV_NOPTS_VALUE) {
pos += st_time;
}
ret = av_seek_frame(anim->pFormatCtx, -1,
pos, AVSEEK_FLAG_BACKWARD);
}
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);
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);
}
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;
}
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 (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;
}
}
}
if(frameFinished && pos_found == 1) {
ffmpeg_postprocess(anim, ibuf, &filter_y);
av_free_packet(&packet);
break;
}
if (anim->next_packet.stream_index == anim->videoStream) {
av_free_packet(&anim->next_packet);
anim->next_packet.stream_index = -1;
}
av_free_packet(&packet);
/* memset(anim->pFrame,...) ?? */
if (ret >= 0) {
ffmpeg_decode_video_frame_scan(anim, pts_to_search);
}
} 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 +1169,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 +1302,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 +1337,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 +1381,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 +1405,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)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,365 @@
#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;
}

@ -319,7 +319,7 @@ ImBuf* IMB_thumb_create(const char* path, ThumbSize size, ThumbSource source, Im
struct anim * anim = NULL;
anim = IMB_open_anim(path, IB_rect | IB_metadata);
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 {

@ -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);
}
}
}

@ -71,12 +71,19 @@ typedef struct StripColorBalance {
} StripColorBalance;
typedef struct StripProxy {
char dir[160];
char file[80];
struct anim *anim;
short size;
short quality;
int pad;
char dir[160]; // custom directory for index and proxy files
// (defaults to BL_proxy)
char file[80]; // custom file
struct anim *anim; // custom proxy anim file
short tc; // time code in use
short quality; // proxy build quality
short build_size_flags;// size flags (see below) of all proxies
// to build
short build_tc_flags; // time code flags (see below) of all tc indices
// to build
} StripProxy;
typedef struct Strip {
@ -288,6 +295,18 @@ typedef struct SpeedControlVars {
#define SEQ_COLOR_BALANCE_INVERSE_GAMMA 2
#define SEQ_COLOR_BALANCE_INVERSE_LIFT 4
/* !!! has to be same as IMB_imbuf.h IMB_PROXY_... and IMB_TC_... */
#define SEQ_PROXY_IMAGE_SIZE_25 1
#define SEQ_PROXY_IMAGE_SIZE_50 2
#define SEQ_PROXY_IMAGE_SIZE_75 4
#define SEQ_PROXY_TC_NONE 0
#define SEQ_PROXY_TC_RECORD_RUN 1
#define SEQ_PROXY_TC_FREE_RUN 2
#define SEQ_PROXY_TC_INTERP_REC_DATE_FREE_RUN 4
#define SEQ_PROXY_TC_ALL 7
/* seq->type WATCH IT: SEQ_EFFECT BIT is used to determine if this is an effect strip!!! */
#define SEQ_IMAGE 0
#define SEQ_META 1

@ -245,6 +245,10 @@ static void rna_Sequence_use_proxy_set(PointerRNA *ptr, int value)
seq->flag |= SEQ_USE_PROXY;
if(seq->strip->proxy == NULL) {
seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
seq->strip->proxy->quality = 90;
seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
seq->strip->proxy->build_size_flags
= SEQ_PROXY_IMAGE_SIZE_25;
}
} else {
seq->flag ^= SEQ_USE_PROXY;
@ -587,6 +591,34 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *scene, PointerRNA *
rna_Sequence_update(bmain, scene, ptr);
}
static int seqproxy_seq_cmp_cb(Sequence *seq, void *arg_pt)
{
struct { Sequence *seq; void *seq_proxy; } *data= arg_pt;
if(seq->strip && seq->strip->proxy == data->seq_proxy) {
data->seq= seq;
return -1; /* done so bail out */
}
return 1;
}
static void rna_Sequence_tcindex_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Editing *ed= seq_give_editing(scene, FALSE);
Sequence *seq;
struct { Sequence *seq; void *seq_proxy; } data;
data.seq= NULL;
data.seq_proxy = ptr->data;
seqbase_recursive_apply(&ed->seqbase, seqproxy_seq_cmp_cb, &data);
seq= data.seq;
reload_sequence_new_file(scene, seq, FALSE);
rna_Sequence_frame_change_update(scene, seq);
}
/* do_versions? */
static float rna_Sequence_opacity_get(PointerRNA *ptr)
{
@ -790,6 +822,19 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem seq_tc_items[]= {
{SEQ_PROXY_TC_NONE, "NONE", 0, "No TC in use", ""},
{SEQ_PROXY_TC_RECORD_RUN, "RECORD_RUN", 0, "Record Run",
"use images in the order as they are recorded"},
{SEQ_PROXY_TC_FREE_RUN, "FREE_RUN", 0, "Free Run",
"use global timestamp written by recording device"},
{SEQ_PROXY_TC_INTERP_REC_DATE_FREE_RUN, "FREE_RUN_REC_DATE",
0, "Free Run (rec date)",
"interpolate a global timestamp using the "
"record date and time written by recording "
"device"},
{0, NULL, 0, NULL, NULL}};
srna = RNA_def_struct(brna, "SequenceProxy", NULL);
RNA_def_struct_ui_text(srna, "Sequence Proxy", "Proxy parameters for a sequence strip");
RNA_def_struct_sdna(srna, "StripProxy");
@ -804,6 +849,42 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, "rna_Sequence_proxy_filepath_get", "rna_Sequence_proxy_filepath_length", "rna_Sequence_proxy_filepath_set");
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
prop= RNA_def_property(srna, "build_25", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_size_flags", SEQ_PROXY_IMAGE_SIZE_25);
RNA_def_property_ui_text(prop, "25%", "Build 25% proxy resolution");
prop= RNA_def_property(srna, "build_50", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_size_flags", SEQ_PROXY_IMAGE_SIZE_50);
RNA_def_property_ui_text(prop, "50%", "Build 50% proxy resolution");
prop= RNA_def_property(srna, "build_75", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_size_flags", SEQ_PROXY_IMAGE_SIZE_75);
RNA_def_property_ui_text(prop, "75%", "Build 75% proxy resolution");
prop= RNA_def_property(srna, "build_record_run", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_tc_flags", SEQ_PROXY_TC_RECORD_RUN);
RNA_def_property_ui_text(prop, "Rec Run", "Build record run time code index");
prop= RNA_def_property(srna, "build_free_run", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_tc_flags", SEQ_PROXY_TC_FREE_RUN);
RNA_def_property_ui_text(prop, "Free Run", "Build free run time code index");
prop= RNA_def_property(srna, "build_free_run_rec_date", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_tc_flags", SEQ_PROXY_TC_INTERP_REC_DATE_FREE_RUN);
RNA_def_property_ui_text(prop, "Free Run (Rec Date)", "Build free run time code index using Record Date/Time");
prop= RNA_def_property(srna, "quality", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "quality");
RNA_def_property_ui_text(prop, "Quality", "JPEG Quality of proxies to build");
RNA_def_property_ui_range(prop, 1, 100, 1, 0);
prop= RNA_def_property(srna, "timecode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "tc");
RNA_def_property_enum_items(prop, seq_tc_items);
RNA_def_property_ui_text(prop, "Timecode", "");
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_tcindex_update");
}
static void rna_def_strip_color_balance(BlenderRNA *brna)
@ -1208,7 +1289,7 @@ static void rna_def_proxy(StructRNA *srna)
prop= RNA_def_property(srna, "use_proxy", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXY);
RNA_def_property_ui_text(prop, "Use Proxy", "Use a preview proxy for this strip");
RNA_def_property_ui_text(prop, "Use Proxy / Timecode", "Use a preview proxy and/or timecode index for this strip");
RNA_def_property_boolean_funcs(prop, NULL, "rna_Sequence_use_proxy_set");
prop= RNA_def_property(srna, "proxy", PROP_POINTER, PROP_NONE);

@ -298,6 +298,8 @@ int WM_jobs_test(struct wmWindowManager *wm, void *owner);
float WM_jobs_progress(struct wmWindowManager *wm, void *owner);
char *WM_jobs_name(struct wmWindowManager *wm, void *owner);
int WM_jobs_is_running(struct wmJob *);
void* WM_jobs_get_customdata(struct wmJob *);
void WM_jobs_customdata(struct wmJob *, void *customdata, void (*free)(void *));
void WM_jobs_timer(struct wmJob *, double timestep, unsigned int note, unsigned int endnote);
void WM_jobs_callbacks(struct wmJob *,

@ -202,6 +202,20 @@ char *WM_jobs_name(wmWindowManager *wm, void *owner)
return NULL;
}
int WM_jobs_is_running(wmJob *steve)
{
return steve->running;
}
void* WM_jobs_get_customdata(wmJob * steve)
{
if (!steve->customdata) {
return steve->run_customdata;
} else {
return steve->customdata;
}
}
void WM_jobs_customdata(wmJob *steve, void *customdata, void (*free)(void *))
{
/* pending job? just free */

@ -552,11 +552,11 @@ elseif(WIN32)
if(WITH_CODEC_FFMPEG)
install(
FILES
${LIBDIR}/ffmpeg/lib/avcodec-52.dll
${LIBDIR}/ffmpeg/lib/avformat-52.dll
${LIBDIR}/ffmpeg/lib/avdevice-52.dll
${LIBDIR}/ffmpeg/lib/avutil-50.dll
${LIBDIR}/ffmpeg/lib/swscale-0.dll
${LIBDIR}/ffmpeg-0.8/lib/avcodec-53.dll
${LIBDIR}/ffmpeg-0.8/lib/avformat-53.dll
${LIBDIR}/ffmpeg-0.8/lib/avdevice-53.dll
${LIBDIR}/ffmpeg-0.8/lib/avutil-51.dll
${LIBDIR}/ffmpeg-0.8/lib/swscale-2.dll
DESTINATION ${TARGETDIR}
)