From 327d413eb3c0c4cf07b71903eaa27e784be172c3 Mon Sep 17 00:00:00 2001 From: Peter Schlaile Date: Tue, 7 Mar 2006 20:01:12 +0000 Subject: this patch features several cleanups and bugfixes for the sequencer: - blur works again (this was a serious bug in gamwarp...) - seperates all sequence effects into a seperate file with a clean interface - thereby fixing some obscure segfaults - seperates the scope views into a seperate file - adds float support to all effects and scope views - removes a bad level call to open_plugin_seq - FFMPEG seeking improved a lot. - FFMPEG compiles with debian sarge version cleanly - Makes hdaudio seek and resample code really work --- source/blender/imbuf/intern/IMB_anim.h | 1 + source/blender/imbuf/intern/anim.c | 160 ++++++++++++++++++++------------- source/blender/imbuf/intern/divers.c | 33 ++++--- source/blender/imbuf/intern/scaling.c | 16 +++- source/blender/imbuf/intern/util.c | 28 +++--- 5 files changed, 147 insertions(+), 91 deletions(-) (limited to 'source/blender/imbuf/intern') diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 5d597aa5463..602b13df4ca 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -153,6 +153,7 @@ struct anim { int orientation; size_t framesize; int interlacing; + int preseek; /* data */ struct ImBuf * ibuf1, * ibuf2; diff --git a/source/blender/imbuf/intern/anim.c b/source/blender/imbuf/intern/anim.c index bd4b268f685..cd238f5013e 100644 --- a/source/blender/imbuf/intern/anim.c +++ b/source/blender/imbuf/intern/anim.c @@ -88,12 +88,19 @@ #ifdef WITH_FFMPEG #include #include +#include + +/* #define FFMPEG_SEEK_DEBUG 1 */ #if LIBAVFORMAT_VERSION_INT < (49 << 16) #define FFMPEG_OLD_FRAME_RATE 1 #else #define FFMPEG_CODEC_IS_POINTER 1 -#define FFMPEG_HAVE_SKIP_FRAME 1 +#define FFMPEG_HAVE_SKIP_OPTS 1 +#endif + +#ifndef FF_ER_CAREFUL +#define FF_ER_CAREFUL FF_ER_CAREFULL #endif #endif @@ -136,6 +143,7 @@ static int startmovie(struct anim * anim) { anim->framesize = dmImageFrameSize(anim->params); anim->curposition = 0; + anim->preseek = 0; /*printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/ return (0); @@ -439,6 +447,7 @@ static int startavi (struct anim *anim) { anim->framesize = anim->x * anim->y * 4; anim->curposition = 0; + anim->preseek = 0; /* printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/ @@ -493,6 +502,18 @@ static ImBuf * avi_fetchibuf (struct anim *anim, int position) { extern void do_init_ffmpeg(); +#ifdef FFMPEG_CODEC_IS_POINTER +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return stream->codec; +} +#else +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return &stream->codec; +} +#endif + static int startffmpeg(struct anim * anim) { int i, videoStream; @@ -519,12 +540,8 @@ static int startffmpeg(struct anim * anim) { /* Find the first video stream */ videoStream=-1; for(i=0; inb_streams; i++) -#ifdef FFMPEG_CODEC_IS_POINTER - if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) -#else - if(pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO) -#endif - { + if(get_codec_from_stream(pFormatCtx->streams[i])->codec_type + == CODEC_TYPE_VIDEO) { videoStream=i; break; } @@ -534,11 +551,7 @@ static int startffmpeg(struct anim * anim) { return -1; } -#ifdef FFMPEG_CODEC_IS_POINTER - pCodecCtx=pFormatCtx->streams[videoStream]->codec; -#else - pCodecCtx=&pFormatCtx->streams[videoStream]->codec; -#endif + pCodecCtx = get_codec_from_stream(pFormatCtx->streams[videoStream]); /* Find the decoder for the video stream */ pCodec=avcodec_find_decoder(pCodecCtx->codec_id); @@ -551,11 +564,11 @@ static int startffmpeg(struct anim * anim) { pCodecCtx->workaround_bugs = 1; pCodecCtx->lowres = 0; pCodecCtx->idct_algo= FF_IDCT_AUTO; -#ifdef FFMPEG_HAVE_SKIP_FRAME +#ifdef FFMPEG_HAVE_SKIP_OPTS pCodecCtx->skip_frame= AVDISCARD_DEFAULT; -#endif pCodecCtx->skip_idct= AVDISCARD_DEFAULT; pCodecCtx->skip_loop_filter= AVDISCARD_DEFAULT; +#endif pCodecCtx->error_resilience= FF_ER_CAREFUL; pCodecCtx->error_concealment= 3; @@ -573,7 +586,9 @@ static int startffmpeg(struct anim * anim) { anim->duration = pFormatCtx->duration * pCodecCtx->frame_rate / pCodecCtx->frame_rate_base / AV_TIME_BASE; #else - anim->duration = pFormatCtx->duration * av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate) / AV_TIME_BASE; + anim->duration = pFormatCtx->duration + * av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate) + / AV_TIME_BASE; #endif anim->params = 0; @@ -605,7 +620,12 @@ static int startffmpeg(struct anim * anim) { return -1; } - /*printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/ + if (pCodecCtx->has_b_frames) { + anim->preseek = 18; /* FIXME: detect gopsize ... */ + } else { + anim->preseek = 0; + } + return (0); } @@ -624,23 +644,50 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { (unsigned char*) ibuf->rect, PIX_FMT_RGBA32, anim->x, anim->y); + if (position != anim->curposition + 1) { + if (position > anim->curposition + 1 + && anim->preseek + && position - (anim->curposition + 1) < anim->preseek) { + while(av_read_frame(anim->pFormatCtx, &packet)>=0) { + if (packet.stream_index == anim->videoStream) { + avcodec_decode_video( + anim->pCodecCtx, + anim->pFrame, &frameFinished, + packet.data, packet.size); + + if (frameFinished) { + anim->curposition++; + } + } + av_free_packet(&packet); + if (position == anim->curposition+1) { + break; + } + } + } + } + if (position != anim->curposition + 1) { int keyframe_found = 0; - int scan_pos = position; - int max_scan = 18; /* max mpeg 1/2 gop size */ #ifdef FFMPEG_OLD_FRAME_RATE - long long pos = (long long) anim->pCodecCtx->frame_rate_base - * position * AV_TIME_BASE - / anim->pCodecCtx->frame_rate; + double frame_rate = + (double) anim->pCodecCtx->frame_rate + / (double) anim->pCodecCtx->frame_rate_base; #else - long long pos = (long long) position * AV_TIME_BASE - / av_q2d(anim->pFormatCtx->streams[anim->videoStream] - ->r_frame_rate); + double frame_rate = + av_q2d(anim->pFormatCtx->streams[anim->videoStream] + ->r_frame_rate); #endif + double time_base = + av_q2d(anim->pFormatCtx->streams[anim->videoStream] + ->time_base); + long long pos = (long long) position * AV_TIME_BASE + / frame_rate; long long st_time = anim->pFormatCtx ->streams[anim->videoStream]->start_time; + if (st_time != AV_NOPTS_VALUE) { - pos += st_time; + pos += st_time * AV_TIME_BASE * time_base; } av_seek_frame(anim->pFormatCtx, -1, @@ -653,49 +700,23 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { if ((packet.flags & PKT_FLAG_KEY) != 0) { keyframe_found = 1; } + av_free_packet(&packet); break; } av_free_packet(&packet); } - /* if all ffmpeg seek bugs are fixed, the following - loop is obsolete ... (but does not hurt very much...) - */ - - while (!keyframe_found && max_scan--) { - scan_pos--; -#ifdef FFMPEG_OLD_FRAME_RATE - pos = (long long) - anim->pCodecCtx->frame_rate_base - * scan_pos * AV_TIME_BASE - / anim->pCodecCtx->frame_rate; -#else - pos = (long long) scan_pos * AV_TIME_BASE - / av_q2d(anim->pFormatCtx - ->streams[anim->videoStream] - ->r_frame_rate); -#endif - av_seek_frame(anim->pFormatCtx, -1, - pos, - AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD); - while(av_read_frame(anim->pFormatCtx, &packet)>=0) { - if(packet.stream_index == anim->videoStream) { - if ((packet.flags & PKT_FLAG_KEY) - != 0) { - keyframe_found = 1; - } - av_free_packet(&packet); - break; - } - av_free_packet(&packet); + if (!keyframe_found) { + int scan_pos = position - anim->preseek; + if (scan_pos < 0) { + scan_pos = 0; } - } - if (max_scan <= 0) { - fprintf(stderr, - "Warning: Key frame not found, " - "doesn't hurt, but _slow_...!\n"); + pos = (long long) scan_pos * AV_TIME_BASE / frame_rate; + if (st_time != AV_NOPTS_VALUE) { + pos += st_time * AV_TIME_BASE * time_base; + } } av_seek_frame(anim->pFormatCtx, -1, @@ -710,6 +731,11 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { && !pos_found) { if (url_ftell(&anim->pFormatCtx->pb) == pos_to_match) { pos_found = 1; + if (anim->pCodecCtx->has_b_frames) { + pos_found++; + /* account for delay caused by + decoding pipeline */ + } } } if(packet.stream_index == anim->videoStream) { @@ -717,7 +743,9 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { anim->pFrame, &frameFinished, packet.data, packet.size); - if(frameFinished && pos_found) { + if (frameFinished && pos_found == 2) { + pos_found = 1; + } else if(frameFinished && pos_found == 1) { unsigned char * p =(unsigned char*) ibuf->rect; unsigned char * e = p + anim->x * anim->y * 4; @@ -924,3 +952,13 @@ struct ImBuf * IMB_anim_nextpic(struct anim * anim) { int IMB_anim_get_duration(struct anim *anim) { return anim->duration; } + +void IMB_anim_set_preseek(struct anim * anim, int preseek) +{ + anim->preseek = preseek; +} + +int IMB_anim_get_preseek(struct anim * anim) +{ + return anim->preseek; +} diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 2fc80f6ddcb..c0018d0b336 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -141,25 +141,32 @@ void IMB_interlace(struct ImBuf *ibuf) void IMB_gamwarp(struct ImBuf *ibuf, double gamma) { uchar gam[256]; - int i, do_float=0; - uchar *rect = (uchar *) ibuf->rect; - float *rectf = ibuf->rect_float; + int i; + uchar *rect; + float *rectf; if (ibuf == 0) return; - if (ibuf->rect == 0) return; - if (ibuf->rect != NULL) do_float = 1; if (gamma == 1.0) return; + rect = (uchar *) ibuf->rect; + rectf = ibuf->rect_float; + gamma = 1.0 / gamma; - for (i = 255 ; i >= 0 ; i--) gam[i] = (255.0 * pow(i / 255.0 , - gamma)) + 0.5; - rect = (uchar *) ibuf->rect; - for (i = ibuf->x * ibuf->y ; i>0 ; i--, rect+=4){ - rect[0] = gam[rect[0]]; - rect[1] = gam[rect[1]]; - rect[2] = gam[rect[2]]; - if (do_float) { + if (rect) { + for (i = 255 ; i >= 0 ; i--) + gam[i] = (255.0 * pow(i / 255.0 , + gamma)) + 0.5; + + for (i = ibuf->x * ibuf->y ; i>0 ; i--, rect+=4){ + rect[0] = gam[rect[0]]; + rect[1] = gam[rect[1]]; + rect[2] = gam[rect[2]]; + } + } + + if (rectf) { + for (i = ibuf->x * ibuf->y ; i>0 ; i--, rectf+=4){ rectf[0] = pow(rectf[0] / 255.0, gamma); rectf[1] = pow(rectf[1] / 255.0, gamma); rectf[2] = pow(rectf[2] / 255.0, gamma); diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index c962f1fbde5..8db51f50ee0 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -964,10 +964,18 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, short newx, short newy) ofsy += stepy; ofsx = 32768; - for (x = newx ; x>0 ; x--){ - if (do_rect) *newrect++ = rect[ofsx >> 16]; - if (do_float) *newrectf++ = rectf[ofsx >> 16]; - ofsx += stepx; + if (do_rect) { + for (x = newx ; x>0 ; x--){ + *newrect++ = rect[ofsx >> 16]; + ofsx += stepx; + } + } + + if (do_float) { + for (x = newx ; x>0 ; x--){ + *newrectf++ = rectf[ofsx >> 16]; + ofsx += stepx; + } } } diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index fdb1bed3870..56a03f56ce2 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -217,6 +217,18 @@ void do_init_ffmpeg() } } +#ifdef FFMPEG_CODEC_IS_POINTER +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return stream->codec; +} +#else +static AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return &stream->codec; +} +#endif + static int isffmpeg (char *filename) { AVFormatContext *pFormatCtx; @@ -243,21 +255,14 @@ static int isffmpeg (char *filename) { /* Find the first video stream */ videoStream=-1; for(i=0; inb_streams; i++) -#ifdef FFMPEG_CODEC_IS_POINTER - if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) -#else - if(pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO) -#endif + if(get_codec_from_stream(pFormatCtx->streams[i]) + ->codec_type==CODEC_TYPE_VIDEO) { videoStream=i; break; } -#ifdef FFMPEG_CODEC_IS_POINTER - pCodecCtx=pFormatCtx->streams[videoStream]->codec; -#else - pCodecCtx=&pFormatCtx->streams[videoStream]->codec; -#endif + pCodecCtx = get_codec_from_stream(pFormatCtx->streams[videoStream]); if(videoStream==-1) { avcodec_close(pCodecCtx); @@ -274,9 +279,6 @@ static int isffmpeg (char *filename) { return 0; } - if(pCodec->capabilities & CODEC_CAP_TRUNCATED) - pCodecCtx->flags|=CODEC_FLAG_TRUNCATED; - if(avcodec_open(pCodecCtx, pCodec)<0) { avcodec_close(pCodecCtx); av_close_input_file(pFormatCtx); -- cgit v1.2.3