diff options
author | Rudolf Polzer <divverent@alientrap.org> | 2011-04-23 18:56:47 +0200 |
---|---|---|
committer | Uoti Urpala <uau@mplayer2.org> | 2011-04-24 03:55:47 +0300 |
commit | 994b21a80a2f37b0d672526739cb742b87f33ad9 (patch) | |
tree | 222e014be69723c4772d5045fee35eb98ffc8a63 | |
parent | 28b3cc0efe7a575cb8004d1b109ce5ca2f2953bb (diff) | |
download | mpv-994b21a80a2f37b0d672526739cb742b87f33ad9.tar.bz2 mpv-994b21a80a2f37b0d672526739cb742b87f33ad9.tar.xz |
vf_*: fix pts values passed to the next filter
Many video filters failed to calculate or even just pass through pts
values for their output frames. Fix this, and also make the two
remaining filters that called vf_next_put_image() twice for the same
input frame (vf_softpulldown, vf_telecine) use vf_queue_frame() so
that e.g. framestepping properly sees both frames.
Changed filters: vf_bmovl, vf_detc, vf_divtc, vf_filmdint, vf_ivtc,
vf_lavc, vf_phase, vf_pullup, vf_softpulldown, vf_telecine, vf_tile,
vf_tinterlace.
-rw-r--r-- | libmpcodecs/pullup.c | 12 | ||||
-rw-r--r-- | libmpcodecs/pullup.h | 5 | ||||
-rw-r--r-- | libmpcodecs/vf.c | 84 | ||||
-rw-r--r-- | libmpcodecs/vf.h | 16 | ||||
-rw-r--r-- | libmpcodecs/vf_bmovl.c | 12 | ||||
-rw-r--r-- | libmpcodecs/vf_detc.c | 13 | ||||
-rw-r--r-- | libmpcodecs/vf_divtc.c | 7 | ||||
-rw-r--r-- | libmpcodecs/vf_filmdint.c | 5 | ||||
-rw-r--r-- | libmpcodecs/vf_ivtc.c | 15 | ||||
-rw-r--r-- | libmpcodecs/vf_lavc.c | 3 | ||||
-rw-r--r-- | libmpcodecs/vf_phase.c | 2 | ||||
-rw-r--r-- | libmpcodecs/vf_pullup.c | 38 | ||||
-rw-r--r-- | libmpcodecs/vf_softpulldown.c | 31 | ||||
-rw-r--r-- | libmpcodecs/vf_telecine.c | 67 | ||||
-rw-r--r-- | libmpcodecs/vf_tile.c | 5 | ||||
-rw-r--r-- | libmpcodecs/vf_tinterlace.c | 10 |
16 files changed, 269 insertions, 56 deletions
diff --git a/libmpcodecs/pullup.c b/libmpcodecs/pullup.c index 2675be6146..b70aa9b56f 100644 --- a/libmpcodecs/pullup.c +++ b/libmpcodecs/pullup.c @@ -22,6 +22,7 @@ #include "config.h" #include "pullup.h" #include "cpudetect.h" +#include "mpcommon.h" @@ -412,7 +413,8 @@ static void check_field_queue(struct pullup_context *c) } } -void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int parity) +void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, + int parity, double pts) { struct pullup_field *f; @@ -428,6 +430,7 @@ void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int f->flags = 0; f->breaks = 0; f->affinity = 0; + f->pts = pts; compute_metric(c, f, parity, f->prev->prev, parity, c->diff, f->diffs); compute_metric(c, parity?f->prev:f, 0, parity?f:f->prev, 1, c->comb, f->comb); @@ -663,12 +666,19 @@ struct pullup_frame *pullup_get_frame(struct pullup_context *c) fr->length = n; fr->parity = c->first->parity; fr->buffer = 0; + fr->pts = 0; for (i = 0; i < n; i++) { /* We cheat and steal the buffer without release+relock */ fr->ifields[i] = c->first->buffer; c->first->buffer = 0; + if (c->first->pts == MP_NOPTS_VALUE || fr->pts == MP_NOPTS_VALUE) + fr->pts = MP_NOPTS_VALUE; + else + fr->pts += c->first->pts; c->first = c->first->next; } + if (fr->pts != MP_NOPTS_VALUE) + fr->pts /= n; if (n == 1) { fr->ofields[fr->parity] = fr->ifields[0]; diff --git a/libmpcodecs/pullup.h b/libmpcodecs/pullup.h index eb7b143da6..0db8f6f894 100644 --- a/libmpcodecs/pullup.h +++ b/libmpcodecs/pullup.h @@ -40,6 +40,7 @@ struct pullup_buffer struct pullup_field { int parity; + double pts; struct pullup_buffer *buffer; unsigned int flags; int breaks; @@ -55,6 +56,7 @@ struct pullup_frame int lock; int length; int parity; + double pts; struct pullup_buffer **ifields, *ofields[2]; struct pullup_buffer *buffer; }; @@ -87,7 +89,8 @@ struct pullup_buffer *pullup_lock_buffer(struct pullup_buffer *b, int parity); void pullup_release_buffer(struct pullup_buffer *b, int parity); struct pullup_buffer *pullup_get_buffer(struct pullup_context *c, int parity); -void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int parity); +void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, + int parity, double pts); void pullup_flush_fields(struct pullup_context *c); struct pullup_frame *pullup_get_frame(struct pullup_context *c); diff --git a/libmpcodecs/vf.c b/libmpcodecs/vf.c index 6355076726..eefdaa3c46 100644 --- a/libmpcodecs/vf.c +++ b/libmpcodecs/vf.c @@ -751,3 +751,87 @@ void vf_uninit_filter_chain(vf_instance_t* vf){ vf=next; } } + +void vf_detc_init_pts_buf(struct vf_detc_pts_buf *p) +{ + p->inpts_prev = MP_NOPTS_VALUE; + p->outpts_prev = MP_NOPTS_VALUE; + p->lastdelta = 0; +} + +static double vf_detc_adjust_pts_internal(struct vf_detc_pts_buf *p, + double pts, bool reset_pattern, + bool skip_frame, double delta, + double boundfactor_minus, + double increasefactor, + double boundfactor_plus) +{ + double newpts; + + if (pts == MP_NOPTS_VALUE) + return pts; + + if (delta <= 0) { + if (p->inpts_prev == MP_NOPTS_VALUE) + delta = 0; + else if(pts == p->inpts_prev) + delta = p->lastdelta; + else + delta = pts - p->inpts_prev; + } + //mp_msg(MSGT_VFILTER, MSGL_INFO, "filmdint: (1) inpts %f (delta: %f, increase: %f)\n", pts, delta, delta * increasefactor); + p->inpts_prev = pts; + p->lastdelta = delta; + + if (skip_frame) + return MP_NOPTS_VALUE; + + // detect bogus deltas and then passthru pts (possibly caused by seeking, or bad input) + if (p->outpts_prev == MP_NOPTS_VALUE || reset_pattern || delta <= 0.0 || delta >= 0.5) { + newpts = pts; + } else { + // turn 5 frames into 4 + newpts = p->outpts_prev + delta * increasefactor; + + // bound to input pts in a sensible way; these numbers come because we + // map frames the following way when ivtc'ing: + // 0/30 -> 0/24 diff=0 + // 1/30 -> 1/24 diff=1/120 + // 2/30 -> - + // 3/30 -> 2/24 diff=-1/60 + // 4/30 -> 3/24 diff=-1/120 + if (newpts < pts - delta * boundfactor_minus) + newpts = pts - delta * boundfactor_minus; + if (newpts > pts + delta * boundfactor_plus) + newpts = pts + delta * boundfactor_plus; + if (newpts < p->outpts_prev) + newpts = p->outpts_prev; // damage control + } + //mp_msg(MSGT_VFILTER, MSGL_INFO, "filmdint: (2) outpts %f (delta: %f)\n", newpts, newpts - p->outpts_prev); + p->outpts_prev = newpts; + + return newpts; +} + +double vf_detc_adjust_pts(struct vf_detc_pts_buf *p, double pts, + bool reset_pattern, bool skip_frame) +{ + // standard telecine (see above) + return vf_detc_adjust_pts_internal(p, pts, reset_pattern, skip_frame, + 0, 0.5, 1.25, 0.25); +} + +double vf_softpulldown_adjust_pts(struct vf_detc_pts_buf *p, double pts, + bool reset_pattern, bool skip_frame, + int last_frame_duration) +{ + // for the softpulldown filter we get: + // 0/60 -> 0/30 + // 2/60 -> 1/30 + // 5/60 -> 2/30 + // 7/60 -> 3/30, 4/30 + return vf_detc_adjust_pts_internal(p, pts, reset_pattern, skip_frame, + 0, 1.0 / last_frame_duration, + 2.0 / last_frame_duration, + 1.0 / last_frame_duration); +} diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index 58cfaaf787..ec1a9c23ff 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -21,6 +21,7 @@ #include "mp_image.h" #include "mpcommon.h" +#include "stdbool.h" struct MPOpts; struct vf_instance; @@ -169,4 +170,19 @@ static inline int norm_qscale(int qscale, int type) return qscale; } +struct vf_detc_pts_buf { + double inpts_prev, outpts_prev; + double lastdelta; +}; +void vf_detc_init_pts_buf(struct vf_detc_pts_buf *p); +/* Adjust pts when detelecining. + * skip_frame: do not render this frame + * reset_pattern: set to 1 if the telecine pattern has reset due to scene cut + */ +double vf_detc_adjust_pts(struct vf_detc_pts_buf *p, double pts, + bool reset_pattern, bool skip_frame); +double vf_softpulldown_adjust_pts(struct vf_detc_pts_buf *p, double pts, + bool reset_pattern, bool skip_frame, + int last_frame_duration); + #endif /* MPLAYER_VF_H */ diff --git a/libmpcodecs/vf_bmovl.c b/libmpcodecs/vf_bmovl.c index 3b46e1ebcc..b6b9940832 100644 --- a/libmpcodecs/vf_bmovl.c +++ b/libmpcodecs/vf_bmovl.c @@ -261,10 +261,10 @@ put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){ else if( strncmp(cmd,"OPAQUE",6)==0 ) vf->priv->opaque=TRUE; else if( strncmp(cmd,"SHOW", 4)==0 ) vf->priv->hidden=FALSE; else if( strncmp(cmd,"HIDE", 4)==0 ) vf->priv->hidden=TRUE; - else if( strncmp(cmd,"FLUSH" ,5)==0 ) return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + else if( strncmp(cmd,"FLUSH" ,5)==0 ) return vf_next_put_image(vf, dmpi, pts); else { mp_msg(MSGT_VFILTER, MSGL_WARN, "\nvf_bmovl: Unknown command: '%s'. Ignoring.\n", cmd); - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, pts); } if(command == CMD_ALPHA) { @@ -283,7 +283,7 @@ put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){ buffer = malloc(imgw*imgh*pxsz); if(!buffer) { mp_msg(MSGT_VFILTER, MSGL_WARN, "\nvf_bmovl: Couldn't allocate temporary buffer! Skipping...\n\n"); - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, pts); } /* pipes/sockets might need multiple calls to read(): */ want = (imgw*imgh*pxsz); @@ -344,7 +344,7 @@ put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){ if( (imgx <= vf->priv->x2) && ( (imgx+imgw) >= vf->priv->x2) ) vf->priv->x2 = imgx; } - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, pts); } for( buf_y=0 ; (buf_y < imgh) && (buf_y < (vf->priv->h-imgy)) ; buf_y++ ) { @@ -402,7 +402,7 @@ put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){ } } - if(vf->priv->hidden) return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + if(vf->priv->hidden) return vf_next_put_image(vf, dmpi, pts); if(vf->priv->opaque) { // Just copy buffer memory to screen for( ypos=vf->priv->y1 ; ypos < vf->priv->y2 ; ypos++ ) { @@ -454,7 +454,7 @@ put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){ } // for xpos } // for ypos } // if !opaque - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, pts); } // put_image static int diff --git a/libmpcodecs/vf_detc.c b/libmpcodecs/vf_detc.c index cf294ac7f7..bbc22fca6c 100644 --- a/libmpcodecs/vf_detc.c +++ b/libmpcodecs/vf_detc.c @@ -45,6 +45,7 @@ struct vf_priv_s { int mode; int (*analyze)(struct vf_priv_s *, mp_image_t *, mp_image_t *); int needread; + struct vf_detc_pts_buf ptsbuf; }; #define COMPE(a,b,e) (abs((a)-(b)) < (((a)+(b))>>(e))) @@ -285,7 +286,7 @@ static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field) } } -static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi) +static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi, double pts) { struct vf_priv_s *p = vf->priv; int dropflag; @@ -306,11 +307,12 @@ static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi) mp_msg(MSGT_VFILTER, MSGL_V, "drop! [%d/%d=%g]\n", p->outframes, p->inframes, (float)p->outframes/p->inframes); p->lastdrop = 0; + vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1); return 0; } p->outframes++; - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 0)); } static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) @@ -335,22 +337,24 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) /* Don't copy anything unless we'll need to read it. */ if (p->needread) copy_image(dmpi, mpi, 2); p->lastdrop = 0; + vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1); break; case TC_PROG: /* Copy and display the whole frame. */ copy_image(dmpi, mpi, 2); - ret = do_put_image(vf, dmpi); + ret = do_put_image(vf, dmpi, pts); break; case TC_IL1: /* Only copy bottom field unless we need to read. */ if (p->needread) copy_image(dmpi, mpi, 2); else copy_image(dmpi, mpi, 1); p->lastdrop = 0; + vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1); break; case TC_IL2: /* Copy top field and show frame, then copy bottom if needed. */ copy_image(dmpi, mpi, 0); - ret = do_put_image(vf, dmpi); + ret = do_put_image(vf, dmpi, pts); if (p->needread) copy_image(dmpi, mpi, 1); break; } @@ -440,6 +444,7 @@ static int vf_open(vf_instance_t *vf, char *args) if (args) parse_args(p, args); p->analyze = anal_funcs[p->mode].func; p->needread = anal_funcs[p->mode].needread; + vf_detc_init_pts_buf(&p->ptsbuf); return 1; } diff --git a/libmpcodecs/vf_divtc.c b/libmpcodecs/vf_divtc.c index d632a4c60d..b3d84d200f 100644 --- a/libmpcodecs/vf_divtc.c +++ b/libmpcodecs/vf_divtc.c @@ -45,6 +45,7 @@ struct vf_priv_s char *bdata; unsigned int *csdata; int *history; + struct vf_detc_pts_buf ptsbuf; }; /* @@ -358,6 +359,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { case 0: imgop(copyop, dmpi, mpi, 0); + vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1); return 0; case 4: @@ -372,12 +374,12 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) imgop(copyop, tmpi, mpi, 0); imgop(deghost_plane, tmpi, dmpi, p->deghost); imgop(copyop, dmpi, mpi, 0); - return vf_next_put_image(vf, tmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, tmpi, vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 0)); } } imgop(copyop, dmpi, mpi, 0); - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 0)); } static int analyze(struct vf_priv_s *p) @@ -706,6 +708,7 @@ static int vf_open(vf_instance_t *vf, char *args) #endif free(args); + vf_detc_init_pts_buf(&p->ptsbuf); return 1; } diff --git a/libmpcodecs/vf_filmdint.c b/libmpcodecs/vf_filmdint.c index c8da011d81..b40a66831a 100644 --- a/libmpcodecs/vf_filmdint.c +++ b/libmpcodecs/vf_filmdint.c @@ -91,6 +91,7 @@ struct vf_priv_s { struct metrics thres; char chflag; double diff_time, merge_time, decode_time, vo_time, filter_time; + struct vf_detc_pts_buf ptsbuf; }; #define PPZ { 2000, 2000, 0, 2000 } @@ -1331,7 +1332,8 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) "" : " @@@@@@@@@@@@@@@@@"); p->merge_time += get_time() - diff_time; - return show_fields ? vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE) : 0; + pts = vf_detc_adjust_pts(&p->ptsbuf, pts, 0, !show_fields); + return show_fields ? vf_next_put_image(vf, dmpi, pts) : 0; } static int query_format(struct vf_instance *vf, unsigned int fmt) @@ -1357,6 +1359,7 @@ static int config(struct vf_instance *vf, unsigned long cxm = 0; unsigned long cym = 0; struct vf_priv_s *p = vf->priv; + vf_detc_init_pts_buf(&p->ptsbuf); // rounding: if(!IMGFMT_IS_RGB(outfmt) && !IMGFMT_IS_BGR(outfmt)){ switch(outfmt){ diff --git a/libmpcodecs/vf_ivtc.c b/libmpcodecs/vf_ivtc.c index 5622ee03b8..966292ff14 100644 --- a/libmpcodecs/vf_ivtc.c +++ b/libmpcodecs/vf_ivtc.c @@ -49,6 +49,7 @@ struct vf_priv_s { int first; int drop, lastdrop, dropnext; int inframes, outframes; + struct vf_detc_pts_buf ptsbuf; }; enum { @@ -426,7 +427,7 @@ static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field) } } -static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi) +static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi, double pts) { struct vf_priv_s *p = vf->priv; int dropflag=0; @@ -448,11 +449,12 @@ static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi) // p->outframes, p->inframes, (float)p->outframes/p->inframes); mp_msg(MSGT_VFILTER, MSGL_V, "!"); p->lastdrop = 0; + vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1); return 0; } p->outframes++; - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 0)); } static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) @@ -464,6 +466,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) if (p->first) { /* hack */ p->first = 0; + vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1); return 1; } @@ -482,22 +485,23 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) ret = 0; p->lastdrop = 0; mp_msg(MSGT_VFILTER, MSGL_V, "DROP\n"); + vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1); break; case F_MERGE: copy_image(p->dmpi, mpi, 0); - ret = do_put_image(vf, p->dmpi); + ret = do_put_image(vf, p->dmpi, pts); copy_image(p->dmpi, mpi, 1); mp_msg(MSGT_VFILTER, MSGL_V, "MERGE\n"); p->dmpi = NULL; break; case F_NEXT: copy_image(p->dmpi, mpi, 2); - ret = do_put_image(vf, p->dmpi); + ret = do_put_image(vf, p->dmpi, pts); mp_msg(MSGT_VFILTER, MSGL_V, "NEXT\n"); p->dmpi = NULL; break; case F_SHOW: - ret = do_put_image(vf, p->dmpi); + ret = do_put_image(vf, p->dmpi, pts); copy_image(p->dmpi, mpi, 2); mp_msg(MSGT_VFILTER, MSGL_V, "OK\n"); p->dmpi = NULL; @@ -537,6 +541,7 @@ static int vf_open(vf_instance_t *vf, char *args) #if HAVE_MMX && HAVE_EBX_AVAILABLE if(gCpuCaps.hasMMX) block_diffs = block_diffs_MMX; #endif + vf_detc_init_pts_buf(&p->ptsbuf); return 1; } diff --git a/libmpcodecs/vf_lavc.c b/libmpcodecs/vf_lavc.c index 63de4ffdf5..c31044ba21 100644 --- a/libmpcodecs/vf_lavc.c +++ b/libmpcodecs/vf_lavc.c @@ -30,7 +30,6 @@ #include "vd_ffmpeg.h" #include "libavcodec/avcodec.h" - struct vf_priv_s { unsigned char* outbuf; int outbuf_size; @@ -114,7 +113,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ dmpi->planes[0]=(unsigned char*)&vf->priv->pes; - return vf_next_put_image(vf,dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf,dmpi, pts); } //===========================================================================// diff --git a/libmpcodecs/vf_phase.c b/libmpcodecs/vf_phase.c index 5b0eaaa17d..b9ea66c506 100644 --- a/libmpcodecs/vf_phase.c +++ b/libmpcodecs/vf_phase.c @@ -237,7 +237,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) &vf->priv->buf[2], mode); } - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, pts); } static void uninit(struct vf_instance *vf) diff --git a/libmpcodecs/vf_pullup.c b/libmpcodecs/vf_pullup.c index 2dafe20b31..356774b060 100644 --- a/libmpcodecs/vf_pullup.c +++ b/libmpcodecs/vf_pullup.c @@ -40,6 +40,7 @@ struct vf_priv_s { int init; int fakecount; char *qbuf; + double lastpts; }; static void init_pullup(struct vf_instance *vf, mp_image_t *mpi) @@ -145,10 +146,35 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) p = mpi->fields & MP_IMGFIELD_TOP_FIRST ? 0 : (mpi->fields & MP_IMGFIELD_ORDERED ? 1 : 0); - pullup_submit_field(c, b, p); - pullup_submit_field(c, b, p^1); - if (mpi->fields & MP_IMGFIELD_REPEAT_FIRST) - pullup_submit_field(c, b, p); + + if (pts == MP_NOPTS_VALUE) { + pullup_submit_field(c, b, p, MP_NOPTS_VALUE); + pullup_submit_field(c, b, p^1, MP_NOPTS_VALUE); + if (mpi->fields & MP_IMGFIELD_REPEAT_FIRST) + pullup_submit_field(c, b, p, MP_NOPTS_VALUE); + } else { + double delta; + if (vf->priv->lastpts == MP_NOPTS_VALUE) + delta = 1001.0/60000.0; // delta = field time distance + else + delta = (pts - vf->priv->lastpts) / 2; + if (delta <= 0.0 || delta >= 0.5) { + pullup_submit_field(c, b, p, pts); + pullup_submit_field(c, b, p^1, pts); + if (mpi->fields & MP_IMGFIELD_REPEAT_FIRST) + pullup_submit_field(c, b, p, pts); + } else { + vf->priv->lastpts = pts; + if (mpi->fields & MP_IMGFIELD_REPEAT_FIRST) { + pullup_submit_field(c, b, p, pts - delta); + pullup_submit_field(c, b, p^1, pts); + pullup_submit_field(c, b, p, pts + delta); + } else { + pullup_submit_field(c, b, p, pts - delta * 0.5); + pullup_submit_field(c, b, p^1, pts + delta * 0.5); + } + } + } pullup_release_buffer(b, 2); @@ -230,7 +256,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) dmpi->qstride = mpi->qstride; dmpi->qscale_type = mpi->qscale_type; } - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, f->pts); } dmpi = vf_get_image(vf->next, mpi->imgfmt, MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE, @@ -249,7 +275,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) dmpi->qstride = mpi->qstride; dmpi->qscale_type = mpi->qscale_type; } - ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + ret = vf_next_put_image(vf, dmpi, f->pts); pullup_release_frame(f); return ret; } diff --git a/libmpcodecs/vf_softpulldown.c b/libmpcodecs/vf_softpulldown.c index ab45c698ce..5bd5e66bfd 100644 --- a/libmpcodecs/vf_softpulldown.c +++ b/libmpcodecs/vf_softpulldown.c @@ -33,8 +33,22 @@ struct vf_priv_s { int state; long long in; long long out; + struct vf_detc_pts_buf ptsbuf; + int last_frame_duration; + double buffered_pts; + mp_image_t *buffered_mpi; + int buffered_last_frame_duration; }; +static int continue_buffered_image(struct vf_instance *vf) +{ + double pts = vf->priv->buffered_pts; + mp_image_t *mpi = vf->priv->buffered_mpi; + vf->priv->out++; + vf->priv->state=0; + return vf_next_put_image(vf, mpi, vf_softpulldown_adjust_pts(&vf->priv->ptsbuf, pts, 0, 0, vf->priv->buffered_last_frame_duration)); +} + static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { mp_image_t *dmpi; @@ -61,7 +75,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) } if (state == 0) { - ret = vf_next_put_image(vf, mpi, MP_NOPTS_VALUE); + ret = vf_next_put_image(vf, mpi, vf_softpulldown_adjust_pts(&vf->priv->ptsbuf, pts, 0, 0, vf->priv->last_frame_duration)); vf->priv->out++; if (flags & MP_IMGFIELD_REPEAT_FIRST) { my_memcpy_pic(dmpi->planes[0], @@ -97,12 +111,13 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) mpi->chroma_width, mpi->chroma_height/2, dmpi->stride[2]*2, mpi->stride[2]*2); } - ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + ret = vf_next_put_image(vf, dmpi, vf_softpulldown_adjust_pts(&vf->priv->ptsbuf, pts, 0, 0, vf->priv->last_frame_duration)); vf->priv->out++; if (flags & MP_IMGFIELD_REPEAT_FIRST) { - ret |= vf_next_put_image(vf, mpi, MP_NOPTS_VALUE); - vf->priv->out++; - state=0; + vf->priv->buffered_mpi = mpi; + vf->priv->buffered_pts = pts; + vf->priv->buffered_last_frame_duration = vf->priv->last_frame_duration; + vf_queue_frame(vf, continue_buffered_image); } else { my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, @@ -125,6 +140,10 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) } vf->priv->state = state; + if (flags & MP_IMGFIELD_REPEAT_FIRST) + vf->priv->last_frame_duration = 3; + else + vf->priv->last_frame_duration = 2; return ret; } @@ -151,6 +170,8 @@ static int vf_open(vf_instance_t *vf, char *args) vf->default_reqs = VFCAP_ACCEPT_STRIDE; vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); vf->priv->state = 0; + vf->priv->last_frame_duration = 2; + vf_detc_init_pts_buf(&vf->priv->ptsbuf); return 1; } diff --git a/libmpcodecs/vf_telecine.c b/libmpcodecs/vf_telecine.c index 9071dfab98..4ae96f2434 100644 --- a/libmpcodecs/vf_telecine.c +++ b/libmpcodecs/vf_telecine.c @@ -31,8 +31,31 @@ struct vf_priv_s { int frame; + double pts; + double lastpts; + mp_image_t *buffered_mpi; }; +static int continue_buffered_image_fullframe(struct vf_instance *vf) +{ + mp_image_t *mpi = vf->priv->buffered_mpi; + mp_image_t *dmpi = vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | + MP_IMGFLAG_PRESERVE, mpi->width, mpi->height); + + memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, + dmpi->stride[0], mpi->stride[0]); + if (mpi->flags & MP_IMGFLAG_PLANAR) { + memcpy_pic(dmpi->planes[1], mpi->planes[1], + mpi->chroma_width, mpi->chroma_height, + dmpi->stride[1], mpi->stride[1]); + memcpy_pic(dmpi->planes[2], mpi->planes[2], + mpi->chroma_width, mpi->chroma_height, + dmpi->stride[2], mpi->stride[2]); + } + return vf_next_put_image(vf, dmpi, vf->priv->pts); +} + static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { mp_image_t *dmpi; @@ -40,14 +63,26 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) vf->priv->frame = (vf->priv->frame+1)%4; - dmpi = vf_get_image(vf->next, mpi->imgfmt, - MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | - MP_IMGFLAG_PRESERVE, mpi->width, mpi->height); + if (pts != MP_NOPTS_VALUE) { + if (vf->priv->lastpts == MP_NOPTS_VALUE) { + vf->priv->pts = pts; + vf->priv->lastpts = pts; + } else { + // we only increase by 80% of input pts at each frame; in the case + // in which we render two frames, we jump back + // this turns 23.98fps perfectly into 29.97fps + vf->priv->pts += 0.8 * (pts - vf->priv->lastpts); + vf->priv->lastpts = pts; + } + } ret = 0; // 0/0 1/1 2/2 2/3 3/0 switch (vf->priv->frame) { case 0: + dmpi = vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | + MP_IMGFLAG_PRESERVE, mpi->width, mpi->height); my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, dmpi->stride[0]*2, mpi->stride[0]*2); @@ -61,21 +96,19 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) mpi->chroma_width, mpi->chroma_height/2, dmpi->stride[2]*2, mpi->stride[2]*2); } - ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + ret = vf_next_put_image(vf, dmpi, vf->priv->pts); + vf->priv->pts = pts; + vf->priv->buffered_mpi = mpi; + vf_queue_frame(vf, continue_buffered_image_fullframe); + return ret; case 1: case 2: - memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, - dmpi->stride[0], mpi->stride[0]); - if (mpi->flags & MP_IMGFLAG_PLANAR) { - memcpy_pic(dmpi->planes[1], mpi->planes[1], - mpi->chroma_width, mpi->chroma_height, - dmpi->stride[1], mpi->stride[1]); - memcpy_pic(dmpi->planes[2], mpi->planes[2], - mpi->chroma_width, mpi->chroma_height, - dmpi->stride[2], mpi->stride[2]); - } - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE) || ret; + vf->priv->buffered_mpi = mpi; + return continue_buffered_image_fullframe(vf); case 3: + dmpi = vf_get_image(vf->next, mpi->imgfmt, + MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | + MP_IMGFLAG_PRESERVE, mpi->width, mpi->height); my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, dmpi->stride[0]*2, mpi->stride[0]*2); @@ -89,7 +122,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) mpi->chroma_width, mpi->chroma_height/2, dmpi->stride[2]*2, mpi->stride[2]*2); } - ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + ret = vf_next_put_image(vf, dmpi, vf->priv->pts); my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, dmpi->stride[0]*2, mpi->stride[0]*2); if (mpi->flags & MP_IMGFLAG_PLANAR) { @@ -142,6 +175,8 @@ static int vf_open(vf_instance_t *vf, char *args) vf->priv->frame = 1; if (args) sscanf(args, "%d", &vf->priv->frame); vf->priv->frame--; + vf->priv->pts = MP_NOPTS_VALUE; + vf->priv->lastpts = MP_NOPTS_VALUE; return 1; } diff --git a/libmpcodecs/vf_tile.c b/libmpcodecs/vf_tile.c index ad3d662875..0b5dac1559 100644 --- a/libmpcodecs/vf_tile.c +++ b/libmpcodecs/vf_tile.c @@ -80,6 +80,7 @@ struct vf_priv_s { /* Work data */ int frame_cur; + double start_pts; }; @@ -147,6 +148,8 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) // /* First frame, delete the background */ // // } + if (t == 0) + priv->start_pts = pts; /* Position of image */ xi = priv->start + (mpi->w + priv->delta) * (t % priv->xtile); @@ -183,7 +186,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) /* Display the composition */ dmpi->width = xw; dmpi->height = yh; - return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + return vf_next_put_image(vf, dmpi, priv->start_pts); } else { /* Skip the frame */ diff --git a/libmpcodecs/vf_tinterlace.c b/libmpcodecs/vf_tinterlace.c index 91ceb6074b..2583d431e9 100644 --- a/libmpcodecs/vf_tinterlace.c +++ b/libmpcodecs/vf_tinterlace.c @@ -76,16 +76,16 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) mpi->chroma_width, mpi->chroma_height, dmpi->stride[2]*2, mpi->stride[2]); } - ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); + ret = vf_next_put_image(vf, dmpi, pts); } break; case 1: if (vf->priv->frame & 1) - ret = vf_next_put_image(vf, mpi, MP_NOPTS_VALUE); + ret = vf_next_put_image(vf, mpi, pts); break; case 2: if ((vf->priv->frame & 1) == 0) - ret = vf |