forked from bartvdbraak/blender
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:
parent
14e7aa25de
commit
33e829819e
@ -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);
|
||||
|
||||
@ -1116,7 +1131,7 @@ static int get_shown_sequences( ListBase * seqbasep, int cfra, int chanshown, Se
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* **********************************************************************
|
||||
proxy management
|
||||
@ -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,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;
|
||||
@ -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
|
||||
|
135
source/blender/imbuf/intern/IMB_indexer.h
Normal file
135
source/blender/imbuf/intern/IMB_indexer.h
Normal file
@ -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,14 +489,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 +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,150 +800,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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
|
1071
source/blender/imbuf/intern/indexer.c
Normal file
1071
source/blender/imbuf/intern/indexer.c
Normal file
File diff suppressed because it is too large
Load Diff
365
source/blender/imbuf/intern/indexer_dv.c
Normal file
365
source/blender/imbuf/intern/indexer_dv.c
Normal file
@ -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)
|
||||
{
|
||||
@ -789,6 +821,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");
|
||||
@ -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}
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user