[MPlayer-dev-eng] [PATCH 2/2] timing: pass through endpts and time last frame correctly.

Reimar Döffinger Reimar.Doeffinger at gmx.de
Sat Apr 29 16:05:29 EEST 2017


Both committed.

On 08.03.2017, at 00:15, Reimar Döffinger <Reimar.Doeffinger at gmx.de> wrote:

> endpts is the only way we can get correct timing
> for the last frame.
> It should also be useful to implement e.g. correctly
> interpolated pts for frame-doubling deinterlacing and
> to fix timing for -nodouble rendering (which draws
> the frame a decode time, so we need to know the approximately
> right time to decode the next frame before it was decoded/filtered).
> 
> Fixes trac issue #2315.
> ---
> libmenu/vf_menu.c             | 10 +++++-----
> libmpcodecs/dec_video.c       | 13 +++++++++----
> libmpcodecs/dec_video.h       |  4 ++--
> libmpcodecs/vf.c              |  4 ++--
> libmpcodecs/vf.h              |  9 +++++----
> libmpcodecs/vf_1bpp.c         |  4 ++--
> libmpcodecs/vf_2xsai.c        |  4 ++--
> libmpcodecs/vf_ass.c          |  4 ++--
> libmpcodecs/vf_blackframe.c   |  4 ++--
> libmpcodecs/vf_bmovl.c        | 14 +++++++-------
> libmpcodecs/vf_boxblur.c      |  4 ++--
> libmpcodecs/vf_crop.c         |  6 +++---
> libmpcodecs/vf_cropdetect.c   |  4 ++--
> libmpcodecs/vf_decimate.c     |  4 ++--
> libmpcodecs/vf_delogo.c       |  4 ++--
> libmpcodecs/vf_denoise3d.c    |  4 ++--
> libmpcodecs/vf_detc.c         |  4 ++--
> libmpcodecs/vf_dint.c         |  4 ++--
> libmpcodecs/vf_divtc.c        |  6 +++---
> libmpcodecs/vf_down3dright.c  |  4 ++--
> libmpcodecs/vf_eq.c           |  4 ++--
> libmpcodecs/vf_eq2.c          |  4 ++--
> libmpcodecs/vf_expand.c       |  8 ++++----
> libmpcodecs/vf_field.c        |  4 ++--
> libmpcodecs/vf_fil.c          |  6 +++---
> libmpcodecs/vf_filmdint.c     |  4 ++--
> libmpcodecs/vf_fixpts.c       |  4 ++--
> libmpcodecs/vf_flip.c         |  6 +++---
> libmpcodecs/vf_framestep.c    |  4 ++--
> libmpcodecs/vf_fspp.c         |  4 ++--
> libmpcodecs/vf_geq.c          |  4 ++--
> libmpcodecs/vf_gradfun.c      |  4 ++--
> libmpcodecs/vf_halfpack.c     |  4 ++--
> libmpcodecs/vf_harddup.c      |  6 +++---
> libmpcodecs/vf_hqdn3d.c       |  4 ++--
> libmpcodecs/vf_hue.c          |  4 ++--
> libmpcodecs/vf_il.c           |  4 ++--
> libmpcodecs/vf_ilpack.c       |  4 ++--
> libmpcodecs/vf_ivtc.c         |  4 ++--
> libmpcodecs/vf_kerndeint.c    |  6 +++---
> libmpcodecs/vf_lavc.c         |  4 ++--
> libmpcodecs/vf_lavfi.c        |  2 +-
> libmpcodecs/vf_mcdeint.c      |  4 ++--
> libmpcodecs/vf_mirror.c       |  4 ++--
> libmpcodecs/vf_noise.c        |  4 ++--
> libmpcodecs/vf_ow.c           |  4 ++--
> libmpcodecs/vf_palette.c      |  4 ++--
> libmpcodecs/vf_perspective.c  |  4 ++--
> libmpcodecs/vf_phase.c        |  4 ++--
> libmpcodecs/vf_pp.c           |  4 ++--
> libmpcodecs/vf_pp7.c          |  4 ++--
> libmpcodecs/vf_pullup.c       |  6 +++---
> libmpcodecs/vf_qp.c           |  4 ++--
> libmpcodecs/vf_rectangle.c    |  4 ++--
> libmpcodecs/vf_remove_logo.c  |  4 ++--
> libmpcodecs/vf_rgbtest.c      |  4 ++--
> libmpcodecs/vf_rotate.c       |  4 ++--
> libmpcodecs/vf_sab.c          |  4 ++--
> libmpcodecs/vf_scale.c        |  4 ++--
> libmpcodecs/vf_screenshot.c   |  4 ++--
> libmpcodecs/vf_smartblur.c    |  4 ++--
> libmpcodecs/vf_softpulldown.c |  8 ++++----
> libmpcodecs/vf_softskip.c     |  4 ++--
> libmpcodecs/vf_spp.c          |  4 ++--
> libmpcodecs/vf_stereo3d.c     |  4 ++--
> libmpcodecs/vf_swapuv.c       |  4 ++--
> libmpcodecs/vf_telecine.c     |  8 ++++----
> libmpcodecs/vf_test.c         |  4 ++--
> libmpcodecs/vf_tfields.c      |  8 ++++----
> libmpcodecs/vf_tile.c         |  4 ++--
> libmpcodecs/vf_tinterlace.c   | 12 ++++++------
> libmpcodecs/vf_unsharp.c      |  4 ++--
> libmpcodecs/vf_uspp.c         |  4 ++--
> libmpcodecs/vf_vo.c           |  9 ++++++++-
> libmpcodecs/vf_yadif.c        |  6 +++---
> libmpcodecs/vf_yuvcsp.c       |  4 ++--
> libmpcodecs/vf_yvu9.c         |  4 ++--
> libmpcodecs/vf_zrmjpeg.c      |  4 ++--
> libmpdemux/demuxer.c          |  9 +++++++++
> libmpdemux/demuxer.h          |  1 +
> libmpdemux/stheader.h         |  2 ++
> mencoder.c                    |  8 ++++----
> mplayer.c                     | 29 ++++++++++++++++++++++-------
> 83 files changed, 237 insertions(+), 197 deletions(-)
> 
> diff --git a/libmenu/vf_menu.c b/libmenu/vf_menu.c
> index cac1c040d..2e601e0dc 100644
> --- a/libmenu/vf_menu.c
> +++ b/libmenu/vf_menu.c
> @@ -54,12 +54,12 @@ struct vf_priv_s {
>   int passthrough;
> };
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts);
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts);
> 
> void vf_menu_pause_update(struct vf_instance *vf) {
>   const vo_functions_t *video_out = mpctx_get_video_out(vf->priv->current->ctx);
>   if(pause_mpi) {
> -    put_image(vf,pause_mpi, MP_NOPTS_VALUE);
> +    put_image(vf,pause_mpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>     // Don't draw the osd atm
>     //vf->control(vf,VFCTRL_DRAW_OSD,NULL);
>     video_out->flip_page();
> @@ -137,14 +137,14 @@ static int key_cb(int code) {
>   return menu_read_key(st_priv->current,code);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>   mp_image_t *dmpi = NULL;
> 
>   if (vf->priv->passthrough) {
>     dmpi=vf_get_image(vf->next, IMGFMT_MPEGPES, MP_IMGTYPE_EXPORT,
>                       0, mpi->w, mpi->h);
>     dmpi->planes[0]=mpi->planes[0];
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf,dmpi, pts, endpts);
>   }
> 
>   // Close all menu who requested it
> @@ -202,7 +202,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>       dmpi->priv      = mpi->priv;
>     }
>   }
> -  return vf_next_put_image(vf,dmpi, pts);
> +  return vf_next_put_image(vf,dmpi, pts, endpts);
> }
> 
> static void uninit(vf_instance_t *vf) {
> diff --git a/libmpcodecs/dec_video.c b/libmpcodecs/dec_video.c
> index 97a9ac29c..dd9380fff 100644
> --- a/libmpcodecs/dec_video.c
> +++ b/libmpcodecs/dec_video.c
> @@ -388,7 +388,7 @@ int init_best_video_codec(sh_video_t *sh_video, char **video_codec_list,
> }
> 
> void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
> -                   int drop_frame, double pts, int *full_frame)
> +                   int drop_frame, double pts, double endpts, int *full_frame)
> {
>     mp_image_t *mpi = NULL;
>     unsigned int t = GetTimer();
> @@ -420,9 +420,12 @@ void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
>             for (i = 0; i < sh_video->num_buffered_pts; i++)
>                 if (sh_video->buffered_pts[i] < pts)
>                     break;
> -            for (j = sh_video->num_buffered_pts; j > i; j--)
> +            for (j = sh_video->num_buffered_pts; j > i; j--) {
>                 sh_video->buffered_pts[j] = sh_video->buffered_pts[j - 1];
> +                sh_video->buffered_endpts[j] = sh_video->buffered_endpts[j - 1];
> +            }
>             sh_video->buffered_pts[i] = pts;
> +            sh_video->buffered_endpts[i] = endpts;
>             sh_video->num_buffered_pts++;
>         }
>     }
> @@ -454,10 +457,12 @@ void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
>         if (sh_video->num_buffered_pts) {
>             sh_video->num_buffered_pts--;
>             sh_video->pts = sh_video->buffered_pts[sh_video->num_buffered_pts];
> +            sh_video->endpts = sh_video->buffered_endpts[sh_video->num_buffered_pts];
>         } else {
>             mp_msg(MSGT_CPLAYER, MSGL_ERR,
>                    "No pts value from demuxer to use for frame!\n");
>             sh_video->pts = MP_NOPTS_VALUE;
> +            sh_video->endpts = MP_NOPTS_VALUE;
>         }
>         if (delay >= 0) {
>             // limit buffered pts only afterwards so we do not get confused
> @@ -479,13 +484,13 @@ void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
>     return mpi;
> }
> 
> -int filter_video(sh_video_t *sh_video, void *frame, double pts)
> +int filter_video(sh_video_t *sh_video, void *frame, double pts, double endpts)
> {
>     mp_image_t *mpi = frame;
>     unsigned int t2 = GetTimer();
>     vf_instance_t *vf = sh_video->vfilter;
>     // apply video filters and call the leaf vo/ve
> -    int ret = vf->put_image(vf, mpi, pts);
> +    int ret = vf->put_image(vf, mpi, pts, endpts);
>     if (ret > 0) {
>         // draw EOSD first so it ends up below the OSD.
>         // Note that changing this is will not work right with vf_ass and the
> diff --git a/libmpcodecs/dec_video.h b/libmpcodecs/dec_video.h
> index 4be420592..2a53a70e5 100644
> --- a/libmpcodecs/dec_video.h
> +++ b/libmpcodecs/dec_video.h
> @@ -29,8 +29,8 @@ void vfm_help(void);
> int init_best_video_codec(sh_video_t *sh_video, char** video_codec_list, char** video_fm_list);
> void uninit_video(sh_video_t *sh_video);
> 
> -void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size, int drop_frame, double pts, int *full_frame);
> -int filter_video(sh_video_t *sh_video, void *frame, double pts);
> +void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size, int drop_frame, double pts, double endpts, int *full_frame);
> +int filter_video(sh_video_t *sh_video, void *frame, double pts, double endpts);
> 
> int get_video_quality_max(sh_video_t *sh_video);
> void set_video_quality(sh_video_t *sh_video, int quality);
> diff --git a/libmpcodecs/vf.c b/libmpcodecs/vf.c
> index d7d0e5f78..046579151 100644
> --- a/libmpcodecs/vf.c
> +++ b/libmpcodecs/vf.c
> @@ -716,14 +716,14 @@ int vf_next_query_format(struct vf_instance *vf, unsigned int fmt){
>     return flags;
> }
> 
> -int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
> +int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts, double endpts){
>     mpi->usage_count--;
>     if (mpi->usage_count < 0) {
>         mp_msg(MSGT_VFILTER, MSGL_V, "Bad mp_image usage count %i in vf_%s (type %i)\n",
>                mpi->usage_count, vf->info->name, mpi->type);
>         mpi->usage_count = 0;
>     }
> -    return vf->next->put_image(vf->next,mpi, pts);
> +    return vf->next->put_image(vf->next,mpi, pts, endpts);
> }
> 
> void vf_next_draw_slice(struct vf_instance *vf,unsigned char** src, int * stride,int w, int h, int x, int y){
> diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h
> index 8fad5f2e8..0276e5a2d 100644
> --- a/libmpcodecs/vf.h
> +++ b/libmpcodecs/vf.h
> @@ -66,7 +66,7 @@ typedef struct vf_instance {
>     void (*get_image)(struct vf_instance *vf,
>         mp_image_t *mpi);
>     int (*put_image)(struct vf_instance *vf,
> -        mp_image_t *mpi, double pts);
> +        mp_image_t *mpi, double pts, double endpts);
>     void (*start_slice)(struct vf_instance *vf,
>         mp_image_t *mpi);
>     void (*draw_slice)(struct vf_instance *vf,
> @@ -109,8 +109,9 @@ typedef struct vf_seteq_s
> #define VFCTRL_INIT_EOSD       15 /* Select EOSD renderer */
> #define VFCTRL_DRAW_EOSD       16 /* Render EOSD */
> #define VFCTRL_GET_PTS         17 /* Return last pts value that reached vf_vo*/
> -#define VFCTRL_SET_DEINTERLACE 18 /* Set deinterlacing status */
> -#define VFCTRL_GET_DEINTERLACE 19 /* Get deinterlacing status */
> +#define VFCTRL_GET_ENDPTS      18 /* Return last endpts value that reached vf_vo*/
> +#define VFCTRL_SET_DEINTERLACE 19 /* Set deinterlacing status */
> +#define VFCTRL_GET_DEINTERLACE 20 /* Get deinterlacing status */
> 
> #include "vfcap.h"
> 
> @@ -138,7 +139,7 @@ int vf_next_config(struct vf_instance *vf,
> int vf_next_control(struct vf_instance *vf, int request, void* data);
> void vf_extra_flip(struct vf_instance *vf);
> int vf_next_query_format(struct vf_instance *vf, unsigned int fmt);
> -int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts);
> +int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts, double endpts);
> void vf_next_draw_slice (struct vf_instance *vf, unsigned char** src, int* stride, int w,int h, int x, int y);
> 
> vf_instance_t* append_filters(vf_instance_t* last);
> diff --git a/libmpcodecs/vf_1bpp.c b/libmpcodecs/vf_1bpp.c
> index 8d1373594..5d09935b3 100644
> --- a/libmpcodecs/vf_1bpp.c
> +++ b/libmpcodecs/vf_1bpp.c
> @@ -123,7 +123,7 @@ static void convert(mp_image_t *mpi, mp_image_t *dmpi, int value0, int value1,in
>     }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     // hope we'll get DR buffer:
> @@ -173,7 +173,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>    return 0;
>     }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf,dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_2xsai.c b/libmpcodecs/vf_2xsai.c
> index a19420ff9..90eb76ee4 100644
> --- a/libmpcodecs/vf_2xsai.c
> +++ b/libmpcodecs/vf_2xsai.c
> @@ -290,7 +290,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,2*width,2*height,2*d_width,2*d_height,flags,outfmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     // hope we'll get DR buffer:
> @@ -302,7 +302,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>                   dmpi->planes[0], dmpi->stride[0],
>                   mpi->w, mpi->h, mpi->bpp/8);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf,dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c
> index a5b50d97e..cc4b8289c 100644
> --- a/libmpcodecs/vf_ass.c
> +++ b/libmpcodecs/vf_ass.c
> @@ -836,7 +836,7 @@ static void prepare_eosd(vf_instance_t *vf, struct mp_eosd_image_list *imgs)
>     vf->priv->prepare_buffer(vf);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     struct mp_eosd_image_list images;
>     eosd_render_frame(pts, &images);
> @@ -844,7 +844,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>     if (images.changed)
>         prepare_eosd(vf, &images);
>     vf->priv->render_frame(vf);
> -    return vf_next_put_image(vf, vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
> }
> 
> static int query_format(struct vf_instance *vf, unsigned int fmt)
> diff --git a/libmpcodecs/vf_blackframe.c b/libmpcodecs/vf_blackframe.c
> index c72552c99..4d745344a 100644
> --- a/libmpcodecs/vf_blackframe.c
> +++ b/libmpcodecs/vf_blackframe.c
> @@ -66,7 +66,7 @@ static int query_format(struct vf_instance *vf, unsigned fmt) {
>     return 0;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     int x, y;
>     int nblack=0, pblack=0;
> @@ -107,7 +107,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     vf_clone_mpi_attributes(dmpi, mpi);
> 
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int control(struct vf_instance *vf, int request, void* data){
> diff --git a/libmpcodecs/vf_bmovl.c b/libmpcodecs/vf_bmovl.c
> index bfbbe0be7..a40dee4d5 100644
> --- a/libmpcodecs/vf_bmovl.c
> +++ b/libmpcodecs/vf_bmovl.c
> @@ -217,7 +217,7 @@ _read_cmd(int fd, char *cmd, char *args) {
> 
> 
> static int
> -put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){
> +put_image(struct vf_instance *vf, mp_image_t* mpi, double pts, double endpts){
>    int buf_x=0, buf_y=0, buf_pos=0;
>    int have, got, want;
>    int xpos=0, ypos=0, pos=0;
> @@ -264,10 +264,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>            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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>            }
> 
>            if(command == CMD_ALPHA) {
> @@ -286,7 +286,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>                }
>                   /* pipes/sockets might need multiple calls to read(): */
>                want = (imgw*imgh*pxsz);
> @@ -347,7 +347,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>            }
> 
>            for( buf_y=0 ; (buf_y < imgh) && (buf_y < (vf->priv->h-imgy)) ; buf_y++ ) {
> @@ -405,7 +405,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
> 
>    if(vf->priv->opaque) {    // Just copy buffer memory to screen
>        for( ypos=vf->priv->y1 ; ypos < vf->priv->y2 ; ypos++ ) {
> @@ -460,7 +460,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
> } // put_image
> 
> static int
> diff --git a/libmpcodecs/vf_boxblur.c b/libmpcodecs/vf_boxblur.c
> index bc1ec8028..004dbea80 100644
> --- a/libmpcodecs/vf_boxblur.c
> +++ b/libmpcodecs/vf_boxblur.c
> @@ -127,7 +127,7 @@ static void vBlur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int s
>         }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>         int cw= mpi->w >> mpi->chroma_x_shift;
>         int ch= mpi->h >> mpi->chroma_y_shift;
> 
> @@ -151,7 +151,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>         vBlur(dmpi->planes[2], dmpi->planes[2], cw,ch,
>                 dmpi->stride[2], dmpi->stride[2], vf->priv->chromaParam.radius, vf->priv->chromaParam.power);
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf,dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_crop.c b/libmpcodecs/vf_crop.c
> index 20b0228d8..784ce0e3b 100644
> --- a/libmpcodecs/vf_crop.c
> +++ b/libmpcodecs/vf_crop.c
> @@ -84,10 +84,10 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,vf->priv->crop_w,vf->priv->crop_h,d_width,d_height,flags,outfmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     if (mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf,vf->dmpi, pts, endpts);
>     dmpi=vf_get_image(vf->next,mpi->imgfmt,
>    MP_IMGTYPE_EXPORT, 0,
>    vf->priv->crop_w, vf->priv->crop_h);
> @@ -108,7 +108,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     }
>     dmpi->stride[0]=mpi->stride[0];
>     dmpi->width=mpi->width;
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf,dmpi, pts, endpts);
> }
> 
> static void start_slice(struct vf_instance *vf, mp_image_t *mpi){
> diff --git a/libmpcodecs/vf_cropdetect.c b/libmpcodecs/vf_cropdetect.c
> index c3de24793..0750418ce 100644
> --- a/libmpcodecs/vf_cropdetect.c
> +++ b/libmpcodecs/vf_cropdetect.c
> @@ -72,7 +72,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     int bpp=mpi->bpp/8;
>     int w,h,x,y,shrink_by;
> @@ -161,7 +161,7 @@ if(++vf->priv->fno>0){        // ignore first 2 frames - they may be empty
> 
> }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf,dmpi, pts, endpts);
> }
> 
> static int query_format(struct vf_instance *vf, unsigned int fmt) {
> diff --git a/libmpcodecs/vf_decimate.c b/libmpcodecs/vf_decimate.c
> index 902c29204..5d4c93734 100644
> --- a/libmpcodecs/vf_decimate.c
> +++ b/libmpcodecs/vf_decimate.c
> @@ -128,7 +128,7 @@ static int diff_to_drop(int hi, int lo, float frac, mp_image_t *old, mp_image_t
>         new->w*(new->bpp/8), new->h, old->stride[0], new->stride[0]);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
> 
> @@ -161,7 +161,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>             mpi->chroma_width, mpi->chroma_height,
>             dmpi->stride[2], mpi->stride[2]);
>     }
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf)
> diff --git a/libmpcodecs/vf_delogo.c b/libmpcodecs/vf_delogo.c
> index add6dc6b0..dd3714122 100644
> --- a/libmpcodecs/vf_delogo.c
> +++ b/libmpcodecs/vf_delogo.c
> @@ -195,7 +195,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     if(mpi->flags&MP_IMGFLAG_DIRECT) {
> @@ -223,7 +223,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     vf_clone_mpi_attributes(dmpi, mpi);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_denoise3d.c b/libmpcodecs/vf_denoise3d.c
> index a952a2228..7619cca33 100644
> --- a/libmpcodecs/vf_denoise3d.c
> +++ b/libmpcodecs/vf_denoise3d.c
> @@ -109,7 +109,7 @@ static void deNoise(unsigned char *Frame,        // mpi->planes[x]
> 
> 
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>         int cw= mpi->w >> mpi->chroma_x_shift;
>         int ch= mpi->h >> mpi->chroma_y_shift;
>         int W = mpi->w, H = mpi->h;
> @@ -142,7 +142,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>                 vf->priv->Coefs[3] + 256);
> 
>         vf->priv->pmpi=dmpi; // save reference image
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_detc.c b/libmpcodecs/vf_detc.c
> index 511ae3160..a27048bb0 100644
> --- a/libmpcodecs/vf_detc.c
> +++ b/libmpcodecs/vf_detc.c
> @@ -310,10 +310,10 @@ static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi)
>         }
> 
>         p->outframes++;
> -        return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
> +        return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>         int ret=0;
>         mp_image_t *dmpi;
> diff --git a/libmpcodecs/vf_dint.c b/libmpcodecs/vf_dint.c
> index ac5bf54a5..18740a177 100644
> --- a/libmpcodecs/vf_dint.c
> +++ b/libmpcodecs/vf_dint.c
> @@ -79,7 +79,7 @@ static int config (struct vf_instance *vf,
>     return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
> }
> 
> -static int put_image (struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image (struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     int8_t rrow0[MAXROWSIZE];
>     int8_t rrow1[MAXROWSIZE];
> @@ -188,7 +188,7 @@ static int put_image (struct vf_instance *vf, mp_image_t *mpi, double pts)
>     }
>     vf->priv->was_dint = 0;
> //    mp_msg (MSGT_VFILTER, MSGL_INFO, "DI:%d/%d ", vf->priv->rdfr, vf->priv->dfr);
> -    return vf_next_put_image (vf, mpi, pts);
> +    return vf_next_put_image(vf, mpi, pts, endpts);
> }
> 
> static int vf_open(vf_instance_t *vf, char *args){
> diff --git a/libmpcodecs/vf_divtc.c b/libmpcodecs/vf_divtc.c
> index 111e16f97..48112a9b6 100644
> --- a/libmpcodecs/vf_divtc.c
> +++ b/libmpcodecs/vf_divtc.c
> @@ -258,7 +258,7 @@ static int match(struct vf_priv_s *p, int *diffs,
>    return m;
>    }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
>    {
>    mp_image_t *dmpi, *tmpi=0;
>    int n, m, f, newphase;
> @@ -373,12 +373,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>             }
>       }
> 
>    imgop(copyop, dmpi, mpi, 0);
> -   return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
> +   return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>    }
> 
> static int analyze(struct vf_priv_s *p)
> diff --git a/libmpcodecs/vf_down3dright.c b/libmpcodecs/vf_down3dright.c
> index f1e1f49b0..d1c015d0f 100644
> --- a/libmpcodecs/vf_down3dright.c
> +++ b/libmpcodecs/vf_down3dright.c
> @@ -96,7 +96,7 @@ static void toright(unsigned char *dst[3], unsigned char *src[3],
>         }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>         mp_image_t *dmpi;
> 
> @@ -110,7 +110,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>         toright(dmpi->planes, mpi->planes, dmpi->stride,
>                 mpi->stride, mpi->w, mpi->h, vf->priv);
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int config(struct vf_instance *vf,
> diff --git a/libmpcodecs/vf_eq.c b/libmpcodecs/vf_eq.c
> index c432b1368..1ee3a5970 100644
> --- a/libmpcodecs/vf_eq.c
> +++ b/libmpcodecs/vf_eq.c
> @@ -132,7 +132,7 @@ static void (*process)(unsigned char *dest, int dstride, unsigned char *src, int
> 
> /* FIXME: add packed yuv version of process */
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>         mp_image_t *dmpi;
> 
> @@ -158,7 +158,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>                         vf->priv->contrast);
>         }
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int control(struct vf_instance *vf, int request, void* data)
> diff --git a/libmpcodecs/vf_eq2.c b/libmpcodecs/vf_eq2.c
> index 275f19698..e02a59c88 100644
> --- a/libmpcodecs/vf_eq2.c
> +++ b/libmpcodecs/vf_eq2.c
> @@ -238,7 +238,7 @@ void apply_lut (eq2_param_t *par, unsigned char *dst, unsigned char *src,
> }
> 
> static
> -int put_image (vf_instance_t *vf, mp_image_t *src, double pts)
> +int put_image (vf_instance_t *vf, mp_image_t *src, double pts, double endpts)
> {
>   unsigned      i;
>   vf_eq2_t      *eq2;
> @@ -278,7 +278,7 @@ int put_image (vf_instance_t *vf, mp_image_t *src, double pts)
>     }
>   }
> 
> -  return vf_next_put_image (vf, dst, pts);
> +  return vf_next_put_image(vf, dst, pts, endpts);
> }
> 
> static
> diff --git a/libmpcodecs/vf_expand.c b/libmpcodecs/vf_expand.c
> index 85fae067c..ef9d9030c 100644
> --- a/libmpcodecs/vf_expand.c
> +++ b/libmpcodecs/vf_expand.c
> @@ -398,12 +398,12 @@ static void draw_slice(struct vf_instance *vf,
>     vf->priv->first_slice = 0;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     if (vf->priv->passthrough) {
>       mp_image_t *dmpi = vf_get_image(vf->next, IMGFMT_MPEGPES,
>                                       MP_IMGTYPE_EXPORT, 0, mpi->w, mpi->h);
>       dmpi->planes[0]=mpi->planes[0];
> -      return vf_next_put_image(vf,dmpi, pts);
> +      return vf_next_put_image(vf, dmpi, pts, endpts);
>     }
> 
>     if(mpi->flags&MP_IMGFLAG_DIRECT || mpi->flags&MP_IMGFLAG_DRAW_CALLBACK){
> @@ -423,7 +423,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>    // we've used DR, so we're ready...
>    if(!(mpi->flags&MP_IMGFLAG_PLANAR))
>        vf->dmpi->planes[1] = mpi->planes[1]; // passthrough rgb8 palette
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
>     }
> 
>     // hope we'll get DR buffer:
> @@ -455,7 +455,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> #ifdef OSD_SUPPORT
>     if(vf->priv->osd) draw_osd(vf,mpi->w,mpi->h);
> #endif
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_field.c b/libmpcodecs/vf_field.c
> index fcf24be0b..1d735c9c3 100644
> --- a/libmpcodecs/vf_field.c
> +++ b/libmpcodecs/vf_field.c
> @@ -38,7 +38,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,width,height/2,d_width,d_height,flags,outfmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
>         MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE,
>         mpi->width, mpi->height/2);
> @@ -56,7 +56,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     } else
>         vf->dmpi->planes[1]=mpi->planes[1]; // passthru bgr8 palette!!!
> 
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_fil.c b/libmpcodecs/vf_fil.c
> index 7df7eb0af..a16ea66a1 100644
> --- a/libmpcodecs/vf_fil.c
> +++ b/libmpcodecs/vf_fil.c
> @@ -63,10 +63,10 @@ static int config(struct vf_instance *vf,
>         (d_width*vf->priv->stridefactor)>>1, 2*d_height/vf->priv->stridefactor, flags, outfmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     if(mpi->flags&MP_IMGFLAG_DIRECT){
>         // we've used DR, so we're ready...
> -        return vf_next_put_image(vf,(mp_image_t*)mpi->priv, pts);
> +        return vf_next_put_image(vf, (mp_image_t*)mpi->priv, pts, endpts);
>     }
> 
>     vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
> @@ -84,7 +84,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     } else
>         vf->dmpi->planes[1]=mpi->planes[1]; // passthru bgr8 palette!!!
> 
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_filmdint.c b/libmpcodecs/vf_filmdint.c
> index 2e43bc1a1..3795170a0 100644
> --- a/libmpcodecs/vf_filmdint.c
> +++ b/libmpcodecs/vf_filmdint.c
> @@ -1136,7 +1136,7 @@ find_breaks(struct vf_priv_s *p, struct frame_stats *s)
> 
> #define ITOC(X) (!(X) ? ' ' : (X) + ((X)>9 ? 'a'-10 : '0'))
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
>     struct vf_priv_s *p = vf->priv;
> @@ -1331,7 +1331,7 @@ 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;
> +    return show_fields ? vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE) : 0;
> }
> 
> static int query_format(struct vf_instance *vf, unsigned int fmt)
> diff --git a/libmpcodecs/vf_fixpts.c b/libmpcodecs/vf_fixpts.c
> index ae32b40d8..6bf17ee40 100644
> --- a/libmpcodecs/vf_fixpts.c
> +++ b/libmpcodecs/vf_fixpts.c
> @@ -38,7 +38,7 @@ struct vf_priv_s {
>     unsigned print:1;
> };
> 
> -static int put_image(vf_instance_t *vf, mp_image_t *src, double pts)
> +static int put_image(vf_instance_t *vf, mp_image_t *src, double pts, double endpts)
> {
>     struct vf_priv_s *p = vf->priv;
> 
> @@ -63,7 +63,7 @@ static int put_image(vf_instance_t *vf, mp_image_t *src, double pts)
>     } else {
>         pts = MP_NOPTS_VALUE;
>     }
> -    return vf_next_put_image(vf, src, pts);
> +    return vf_next_put_image(vf, src, pts, endpts);
> }
> 
> static void uninit(vf_instance_t *vf)
> diff --git a/libmpcodecs/vf_flip.c b/libmpcodecs/vf_flip.c
> index e8660ceb5..742e9fdfb 100644
> --- a/libmpcodecs/vf_flip.c
> +++ b/libmpcodecs/vf_flip.c
> @@ -59,12 +59,12 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     if(mpi->flags&MP_IMGFLAG_DIRECT){
>    // we've used DR, so we're ready...
>    if(!(mpi->flags&MP_IMGFLAG_PLANAR))
>        ((mp_image_t*)mpi->priv)->planes[1] = mpi->planes[1]; // passthrough rgb8 palette
> -    return vf_next_put_image(vf,(mp_image_t*)mpi->priv, pts);
> +    return vf_next_put_image(vf, (mp_image_t*)mpi->priv, pts, endpts);
>     }
> 
>     vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
> @@ -85,7 +85,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     } else
>    vf->dmpi->planes[1]=mpi->planes[1]; // passthru bgr8 palette!!!
> 
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_framestep.c b/libmpcodecs/vf_framestep.c
> index 701e6afba..8a126790b 100644
> --- a/libmpcodecs/vf_framestep.c
> +++ b/libmpcodecs/vf_framestep.c
> @@ -89,7 +89,7 @@ struct vf_priv_s {
> };
> 
> /* Filter handler */
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t        *dmpi;
>     struct vf_priv_s  *priv;
> @@ -139,7 +139,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>         dmpi->height    = mpi->height;
> 
>         /* Chain to next filter / output ... */
> -        return vf_next_put_image(vf, dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
>     }
> 
>     /* Skip the frame */
> diff --git a/libmpcodecs/vf_fspp.c b/libmpcodecs/vf_fspp.c
> index 09b90096b..9bb967710 100644
> --- a/libmpcodecs/vf_fspp.c
> +++ b/libmpcodecs/vf_fspp.c
> @@ -523,7 +523,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi)
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
>     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
> @@ -574,7 +574,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> #if HAVE_MMXEXT_INLINE
>     if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
> #endif
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf)
> diff --git a/libmpcodecs/vf_geq.c b/libmpcodecs/vf_geq.c
> index 6360f5da1..6414ec3b2 100644
> --- a/libmpcodecs/vf_geq.c
> +++ b/libmpcodecs/vf_geq.c
> @@ -78,7 +78,7 @@ static double cr(void *vf, double x, double y){
>     return getpix(vf, x, y, 2);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     int x,y, plane;
> 
> @@ -124,7 +124,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     vf->priv->framenum++;
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_gradfun.c b/libmpcodecs/vf_gradfun.c
> index 2e64a42c8..8e84027b1 100644
> --- a/libmpcodecs/vf_gradfun.c
> +++ b/libmpcodecs/vf_gradfun.c
> @@ -295,7 +295,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi)
>     mpi->flags |= MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi = vf->dmpi;
>     int p;
> @@ -326,7 +326,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>                        dmpi->stride[p], mpi->stride[p]);
>     }
> 
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int query_format(struct vf_instance *vf, unsigned int fmt)
> diff --git a/libmpcodecs/vf_halfpack.c b/libmpcodecs/vf_halfpack.c
> index 981d09e28..2b4c8c669 100644
> --- a/libmpcodecs/vf_halfpack.c
> +++ b/libmpcodecs/vf_halfpack.c
> @@ -163,7 +163,7 @@ static void (*halfpack)(unsigned char *dst, unsigned char *src[3],
>    int dststride, int srcstride[3], int w, int h);
> 
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>    const uint8_t *src[MP_MAX_PLANES] = {
>        mpi->planes[0] + mpi->stride[0]*vf->priv->field,
> @@ -187,7 +187,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>            mpi->stride, mpi->w, mpi->h);
>    }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int config(struct vf_instance *vf,
> diff --git a/libmpcodecs/vf_harddup.c b/libmpcodecs/vf_harddup.c
> index 5b6c2ff01..249b37ae9 100644
> --- a/libmpcodecs/vf_harddup.c
> +++ b/libmpcodecs/vf_harddup.c
> @@ -31,7 +31,7 @@ struct vf_priv_s {
>     mp_image_t *last_mpi;
> };
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
> 
> @@ -49,7 +49,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>         dmpi->stride[2] = mpi->stride[2];
>     }
> 
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int control(struct vf_instance *vf, int request, void* data)
> @@ -61,7 +61,7 @@ static int control(struct vf_instance *vf, int request, void* data)
>         // has been called earlier in the filter chain
>         // since the last put_image. This is reasonable
>         // because we're handling a duplicate frame!
> -        if (put_image(vf, vf->priv->last_mpi, MP_NOPTS_VALUE))
> +        if (put_image(vf, vf->priv->last_mpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE))
>             return CONTROL_TRUE;
>         break;
>     }
> diff --git a/libmpcodecs/vf_hqdn3d.c b/libmpcodecs/vf_hqdn3d.c
> index eba3439d8..922254492 100644
> --- a/libmpcodecs/vf_hqdn3d.c
> +++ b/libmpcodecs/vf_hqdn3d.c
> @@ -208,7 +208,7 @@ static void deNoise(unsigned char *Frame,        // mpi->planes[x]
> }
> 
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>         int cw= mpi->w >> mpi->chroma_x_shift;
>         int ch= mpi->h >> mpi->chroma_y_shift;
>         int W = mpi->w, H = mpi->h;
> @@ -238,7 +238,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>                 vf->priv->Coefs[2],
>                 vf->priv->Coefs[3]);
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_hue.c b/libmpcodecs/vf_hue.c
> index 177142f03..80a3bc0c3 100644
> --- a/libmpcodecs/vf_hue.c
> +++ b/libmpcodecs/vf_hue.c
> @@ -76,7 +76,7 @@ static void (*process)(uint8_t *udst, uint8_t *vdst, uint8_t *usrc, uint8_t *vsr
> 
> /* FIXME: add packed yuv version of process */
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>         mp_image_t *dmpi;
> 
> @@ -107,7 +107,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>                         vf->priv->hue, vf->priv->saturation);
>         }
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int control(struct vf_instance *vf, int request, void* data)
> diff --git a/libmpcodecs/vf_il.c b/libmpcodecs/vf_il.c
> index 210e30d3f..079ea791d 100644
> --- a/libmpcodecs/vf_il.c
> +++ b/libmpcodecs/vf_il.c
> @@ -73,7 +73,7 @@ static void interleave(uint8_t *dst, uint8_t *src, int w, int h, int dstStride,
>     }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     int w;
>     FilterParam *luma  = &vf->priv->lumaParam;
>     FilterParam *chroma= &vf->priv->chromaParam;
> @@ -100,7 +100,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>             dmpi->stride[2], mpi->stride[2], chroma->interleave, luma->swap);
>     }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_ilpack.c b/libmpcodecs/vf_ilpack.c
> index 731d93f20..214c07c62 100644
> --- a/libmpcodecs/vf_ilpack.c
> +++ b/libmpcodecs/vf_ilpack.c
> @@ -373,7 +373,7 @@ static void ilpack(unsigned char *dst, unsigned char *src[3],
> }
> 
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
> 
> @@ -384,7 +384,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> 
>     ilpack(dmpi->planes[0], mpi->planes, dmpi->stride[0], mpi->stride, mpi->w, mpi->h, vf->priv->pack);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int config(struct vf_instance *vf,
> diff --git a/libmpcodecs/vf_ivtc.c b/libmpcodecs/vf_ivtc.c
> index 5a19d24ab..9b41533fe 100644
> --- a/libmpcodecs/vf_ivtc.c
> +++ b/libmpcodecs/vf_ivtc.c
> @@ -452,10 +452,10 @@ static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi)
>     }
> 
>     p->outframes++;
> -    return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
> +    return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     int ret=0;
>     struct vf_priv_s *p = vf->priv;
> diff --git a/libmpcodecs/vf_kerndeint.c b/libmpcodecs/vf_kerndeint.c
> index c5197fc54..f69c6e67c 100644
> --- a/libmpcodecs/vf_kerndeint.c
> +++ b/libmpcodecs/vf_kerndeint.c
> @@ -74,7 +74,7 @@ static inline int IsYUY2(mp_image_t *mpi)
> #define PLANAR_U 1
> #define PLANAR_V 2
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     int cw= mpi->w >> mpi->chroma_x_shift;
>     int ch= mpi->h >> mpi->chroma_y_shift;
>     int W = mpi->w, H = mpi->h;
> @@ -98,7 +98,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     mp_image_t *dmpi, *pmpi;
> 
>     if(!vf->priv->do_deinterlace)
> -        return vf_next_put_image(vf, mpi, pts);
> +        return vf_next_put_image(vf, mpi, pts, endpts);
> 
>     dmpi=vf_get_image(vf->next,mpi->imgfmt,
>         MP_IMGTYPE_IP, MP_IMGFLAG_ACCEPT_STRIDE,
> @@ -273,7 +273,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>         }
>     }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_lavc.c b/libmpcodecs/vf_lavc.c
> index 62dcf91a4..e6bbc50d3 100644
> --- a/libmpcodecs/vf_lavc.c
> +++ b/libmpcodecs/vf_lavc.c
> @@ -82,7 +82,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,width,height,d_width,d_height,flags,IMGFMT_MPEGPES);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t* dmpi;
>     int out_size;
>     AVFrame *pic= vf->priv->pic;
> @@ -116,7 +116,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, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_lavfi.c b/libmpcodecs/vf_lavfi.c
> index 0f6e71a05..905b13bfe 100644
> --- a/libmpcodecs/vf_lavfi.c
> +++ b/libmpcodecs/vf_lavfi.c
> @@ -300,7 +300,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi)
>     mpi->priv = buf;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     AVFilterBufferRef *buf;
>     mp_image_t *cmpi = NULL;
> diff --git a/libmpcodecs/vf_mcdeint.c b/libmpcodecs/vf_mcdeint.c
> index 1b2d1bbaf..f2fc4711c 100644
> --- a/libmpcodecs/vf_mcdeint.c
> +++ b/libmpcodecs/vf_mcdeint.c
> @@ -282,7 +282,7 @@ return; //caused problems, dunno why
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
> @@ -298,7 +298,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_mirror.c b/libmpcodecs/vf_mirror.c
> index 5ac05e914..06c299ba1 100644
> --- a/libmpcodecs/vf_mirror.c
> +++ b/libmpcodecs/vf_mirror.c
> @@ -83,7 +83,7 @@ static void mirror(unsigned char* dst,unsigned char* src,int dststride,int srcst
> 
> //===========================================================================//
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     // hope we'll get DR buffer:
> @@ -108,7 +108,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>         dmpi->planes[1]=mpi->planes[1]; // passthrough rgb8 palette
>     }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_noise.c b/libmpcodecs/vf_noise.c
> index 0fe9dcb96..244294a7b 100644
> --- a/libmpcodecs/vf_noise.c
> +++ b/libmpcodecs/vf_noise.c
> @@ -339,7 +339,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>         mp_image_t *dmpi;
> 
>         if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
> @@ -365,7 +365,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>         if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
> #endif
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_ow.c b/libmpcodecs/vf_ow.c
> index f7fb02db7..4647068cd 100644
> --- a/libmpcodecs/vf_ow.c
> +++ b/libmpcodecs/vf_ow.c
> @@ -233,7 +233,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
> @@ -251,7 +251,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     filter(vf->priv, dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, 0);
>     filter(vf->priv, dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, 0);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_palette.c b/libmpcodecs/vf_palette.c
> index fc6764b0b..eafac4d02 100644
> --- a/libmpcodecs/vf_palette.c
> +++ b/libmpcodecs/vf_palette.c
> @@ -112,7 +112,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,width,height,d_width,d_height,flags,vf->priv->fmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     uint8_t *old_palette = mpi->planes[1];
> 
> @@ -171,7 +171,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     }
>     mpi->planes[1] = old_palette;
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_perspective.c b/libmpcodecs/vf_perspective.c
> index f5a9d6be3..e826195ab 100644
> --- a/libmpcodecs/vf_perspective.c
> +++ b/libmpcodecs/vf_perspective.c
> @@ -260,7 +260,7 @@ static inline void resampleLinear(uint8_t *dst, uint8_t *src, int w, int h, int
>     }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     int cw= mpi->w >> mpi->chroma_x_shift;
>     int ch= mpi->h >> mpi->chroma_y_shift;
> 
> @@ -286,7 +286,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>                 vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift);
>     }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_phase.c b/libmpcodecs/vf_phase.c
> index 101290dec..790ffa199 100644
> --- a/libmpcodecs/vf_phase.c
> +++ b/libmpcodecs/vf_phase.c
> @@ -196,7 +196,7 @@ static enum mode analyze_plane(unsigned char *old, unsigned char *new,
>    return mode;
>    }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
>    {
>    mp_image_t *dmpi;
>    int w;
> @@ -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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>    }
> 
> static void uninit(struct vf_instance *vf)
> diff --git a/libmpcodecs/vf_pp.c b/libmpcodecs/vf_pp.c
> index a26b28065..9721554d0 100644
> --- a/libmpcodecs/vf_pp.c
> +++ b/libmpcodecs/vf_pp.c
> @@ -128,7 +128,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
>    // no DR, so get a new image! hope we'll get DR buffer:
>    vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
> @@ -153,7 +153,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>            mpi->pict_type);
> #endif
>     }
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_pp7.c b/libmpcodecs/vf_pp7.c
> index e47d642ed..6d6963db6 100644
> --- a/libmpcodecs/vf_pp7.c
> +++ b/libmpcodecs/vf_pp7.c
> @@ -372,7 +372,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     if(mpi->flags&MP_IMGFLAG_DIRECT){
> @@ -404,7 +404,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
> #endif
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_pullup.c b/libmpcodecs/vf_pullup.c
> index 5d08768b7..09dbd0f42 100644
> --- a/libmpcodecs/vf_pullup.c
> +++ b/libmpcodecs/vf_pullup.c
> @@ -104,7 +104,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi)
> }
> #endif
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     struct pullup_context *c = vf->priv->ctx;
>     struct pullup_buffer *b;
> @@ -230,7 +230,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>     }
>     dmpi = vf_get_image(vf->next, mpi->imgfmt,
>         MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE,
> @@ -249,7 +249,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>     pullup_release_frame(f);
>     return ret;
> }
> diff --git a/libmpcodecs/vf_qp.c b/libmpcodecs/vf_qp.c
> index 8dd935e59..31c9b5060 100644
> --- a/libmpcodecs/vf_qp.c
> +++ b/libmpcodecs/vf_qp.c
> @@ -99,7 +99,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>         mp_image_t *dmpi;
>         int x,y;
> 
> @@ -139,7 +139,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>             }
>         }
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_rectangle.c b/libmpcodecs/vf_rectangle.c
> index 21bc209de..c169246dc 100644
> --- a/libmpcodecs/vf_rectangle.c
> +++ b/libmpcodecs/vf_rectangle.c
> @@ -83,7 +83,7 @@ control(struct vf_instance *vf, int request, void *data)
>     return 0;
> }
> static int
> -put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){
> +put_image(struct vf_instance *vf, mp_image_t* mpi, double pts, double endpts){
>     mp_image_t* dmpi;
>     unsigned int bpp = mpi->bpp / 8;
>     int x, y, w, h;
> @@ -152,7 +152,7 @@ put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){
>             p += dmpi->stride[0];
>         }
>     }
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int
> diff --git a/libmpcodecs/vf_remove_logo.c b/libmpcodecs/vf_remove_logo.c
> index 7469ced1d..0841ef6aa 100644
> --- a/libmpcodecs/vf_remove_logo.c
> +++ b/libmpcodecs/vf_remove_logo.c
> @@ -774,7 +774,7 @@ static void convert_yv12(const vf_instance_t * const vf, const char * const sour
>  * filter, has the logo removed by the filter, and is then sent to the next
>  * filter.
>  */
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     dmpi=vf_get_image(vf->next,vf->priv->fmt,
> @@ -813,7 +813,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>         return 0;
>     }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_rgbtest.c b/libmpcodecs/vf_rgbtest.c
> index cbed6ed36..1e15e71eb 100644
> --- a/libmpcodecs/vf_rgbtest.c
> +++ b/libmpcodecs/vf_rgbtest.c
> @@ -113,7 +113,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,width,height,d_width,d_height,flags,vf->priv->fmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     int x, y;
>     int w = vf->priv->w > 0 ? vf->priv->w : mpi->w;
> @@ -137,7 +137,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>          }
>      }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_rotate.c b/libmpcodecs/vf_rotate.c
> index 08d73bec2..8abf6c94a 100644
> --- a/libmpcodecs/vf_rotate.c
> +++ b/libmpcodecs/vf_rotate.c
> @@ -84,7 +84,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,height,width,d_height,d_width,flags,outfmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     // hope we'll get DR buffer:
> @@ -109,7 +109,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>         dmpi->planes[1] = mpi->planes[1]; // passthrough rgb8 palette
>     }
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_sab.c b/libmpcodecs/vf_sab.c
> index 203c468dd..b131c394f 100644
> --- a/libmpcodecs/vf_sab.c
> +++ b/libmpcodecs/vf_sab.c
> @@ -241,7 +241,7 @@ if((x/32)&1){
>     }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     int cw= mpi->w >> mpi->chroma_x_shift;
>     int ch= mpi->h >> mpi->chroma_y_shift;
> 
> @@ -255,7 +255,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     blur(dmpi->planes[1], mpi->planes[1], cw    , ch   , dmpi->stride[1], mpi->stride[1], &vf->priv->chroma);
>     blur(dmpi->planes[2], mpi->planes[2], cw    , ch   , dmpi->stride[2], mpi->stride[2], &vf->priv->chroma);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_scale.c b/libmpcodecs/vf_scale.c
> index 8eca5120a..ef50261ea 100644
> --- a/libmpcodecs/vf_scale.c
> +++ b/libmpcodecs/vf_scale.c
> @@ -459,7 +459,7 @@ static void draw_slice(struct vf_instance *vf,
>     scale(vf->priv->ctx, vf->priv->ctx2, src, stride, y, h, dmpi->planes, dmpi->stride, vf->priv->interlaced);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi=mpi->priv;
> 
> //  printf("vf_scale::put_image(): processing whole frame! dmpi=%p flag=%d\n",
> @@ -483,7 +483,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     if(vf->priv->palette) dmpi->planes[1]=vf->priv->palette; // export palette!
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int control(struct vf_instance *vf, int request, void* data){
> diff --git a/libmpcodecs/vf_screenshot.c b/libmpcodecs/vf_screenshot.c
> index 992ea6df3..9aafac3a2 100644
> --- a/libmpcodecs/vf_screenshot.c
> +++ b/libmpcodecs/vf_screenshot.c
> @@ -194,7 +194,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi)
>     mpi->priv=vf->dmpi;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi = (mp_image_t *)mpi->priv;
> 
> @@ -224,7 +224,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>         vf->priv->store_slices = 0;
>     }
> 
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int control (vf_instance_t *vf, int request, void *data)
> diff --git a/libmpcodecs/vf_smartblur.c b/libmpcodecs/vf_smartblur.c
> index 0ccd36938..6de67bf5e 100644
> --- a/libmpcodecs/vf_smartblur.c
> +++ b/libmpcodecs/vf_smartblur.c
> @@ -182,7 +182,7 @@ static inline void blur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride,
>     }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     int cw= mpi->w >> mpi->chroma_x_shift;
>     int ch= mpi->h >> mpi->chroma_y_shift;
>     int threshold = vf->priv->luma.threshold || vf->priv->chroma.threshold;
> @@ -198,7 +198,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     blur(dmpi->planes[1], mpi->planes[1], cw    , ch   , dmpi->stride[1], mpi->stride[1], &vf->priv->chroma);
>     blur(dmpi->planes[2], mpi->planes[2], cw    , ch   , dmpi->stride[2], mpi->stride[2], &vf->priv->chroma);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_softpulldown.c b/libmpcodecs/vf_softpulldown.c
> index 1a66e5607..fed233971 100644
> --- a/libmpcodecs/vf_softpulldown.c
> +++ b/libmpcodecs/vf_softpulldown.c
> @@ -35,7 +35,7 @@ struct vf_priv_s {
>     long long out;
> };
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
>     int ret = 0;
> @@ -61,7 +61,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         vf->priv->out++;
>         if (flags & MP_IMGFIELD_REPEAT_FIRST) {
>             my_memcpy_pic(dmpi->planes[0],
> @@ -97,10 +97,10 @@ 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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         vf->priv->out++;
>         if (flags & MP_IMGFIELD_REPEAT_FIRST) {
> -            ret |= vf_next_put_image(vf, mpi, MP_NOPTS_VALUE);
> +            ret |= vf_next_put_image(vf, mpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>             vf->priv->out++;
>             state=0;
>         } else {
> diff --git a/libmpcodecs/vf_softskip.c b/libmpcodecs/vf_softskip.c
> index 150c3e7b7..c0189949f 100644
> --- a/libmpcodecs/vf_softskip.c
> +++ b/libmpcodecs/vf_softskip.c
> @@ -31,7 +31,7 @@ struct vf_priv_s {
>     int skipflag;
> };
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
> 
> @@ -51,7 +51,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>         dmpi->stride[2] = mpi->stride[2];
>     }
> 
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int control(struct vf_instance *vf, int request, void* data)
> diff --git a/libmpcodecs/vf_spp.c b/libmpcodecs/vf_spp.c
> index 19257fb09..97cacdc6f 100644
> --- a/libmpcodecs/vf_spp.c
> +++ b/libmpcodecs/vf_spp.c
> @@ -470,7 +470,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>         mp_image_t *dmpi;
> 
>         if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
> @@ -519,7 +519,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>         if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
> #endif
> 
> -        return vf_next_put_image(vf,dmpi, pts);
> +        return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_stereo3d.c b/libmpcodecs/vf_stereo3d.c
> index f26d95df3..641519e32 100644
> --- a/libmpcodecs/vf_stereo3d.c
> +++ b/libmpcodecs/vf_stereo3d.c
> @@ -283,7 +283,7 @@ static int config(struct vf_instance *vf, int width, int height, int d_width,
>                           d_width, d_height, flags, outfmt);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
>     if (vf->priv->in.fmt == vf->priv->out.fmt) { //nothing to do
> @@ -384,7 +384,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>             break;
>         }
>     }
> -    return vf_next_put_image(vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static int query_format(struct vf_instance *vf, unsigned int fmt)
> diff --git a/libmpcodecs/vf_swapuv.c b/libmpcodecs/vf_swapuv.c
> index 4d0e8fcb1..c8c0d61f9 100644
> --- a/libmpcodecs/vf_swapuv.c
> +++ b/libmpcodecs/vf_swapuv.c
> @@ -48,7 +48,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->priv=(void*)dmpi;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     if(mpi->flags&MP_IMGFLAG_DIRECT){
> @@ -67,7 +67,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     vf_clone_mpi_attributes(dmpi, mpi);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_telecine.c b/libmpcodecs/vf_telecine.c
> index 3ffa87faf..3d90c98d6 100644
> --- a/libmpcodecs/vf_telecine.c
> +++ b/libmpcodecs/vf_telecine.c
> @@ -33,7 +33,7 @@ struct vf_priv_s {
>     int frame;
> };
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t *dmpi;
>     int ret;
> @@ -63,7 +63,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>                 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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         /* Fallthrough */
>     case 1:
>     case 2:
> @@ -77,7 +77,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>                 chroma_width, mpi->chroma_height,
>                 dmpi->stride[2], mpi->stride[2]);
>         }
> -        return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE) || ret;
> +        return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE) || ret;
>     case 3:
>         my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0],
>             mpi->planes[0]+mpi->stride[0], w, mpi->h/2,
> @@ -92,7 +92,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>                 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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         my_memcpy_pic(dmpi->planes[0], mpi->planes[0], w, mpi->h/2,
>             dmpi->stride[0]*2, mpi->stride[0]*2);
>         if (mpi->flags & MP_IMGFLAG_PLANAR) {
> diff --git a/libmpcodecs/vf_test.c b/libmpcodecs/vf_test.c
> index bef06120e..a96e077c0 100644
> --- a/libmpcodecs/vf_test.c
> +++ b/libmpcodecs/vf_test.c
> @@ -269,7 +269,7 @@ static void ring2Test(uint8_t *dst, int stride, int off)
>         }
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     int frame= vf->priv->frame_num;
> 
> @@ -302,7 +302,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     frame++;
>     vf->priv->frame_num= frame;
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_tfields.c b/libmpcodecs/vf_tfields.c
> index 7eec78673..e97376220 100644
> --- a/libmpcodecs/vf_tfields.c
> +++ b/libmpcodecs/vf_tfields.c
> @@ -328,7 +328,7 @@ static void (*qpel_4tap)(unsigned char *d, unsigned char *s, int w, int h, int d
> 
> static int continue_buffered_image(struct vf_instance *vf);
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>    vf->priv->buffered_mpi = mpi;
>    vf->priv->buffered_pts = pts;
> @@ -392,7 +392,7 @@ static int continue_buffered_image(struct vf_instance *vf)
>                dmpi->stride[1] = 2*mpi->stride[1];
>                dmpi->stride[2] = 2*mpi->stride[2];
>            }
> -            ret |= vf_next_put_image(vf, dmpi, calc_pts(pts, i));
> +            ret |= vf_next_put_image(vf, dmpi, calc_pts(pts, i), MP_NOPTS_VALUE);
>            if (correct_pts)
>                break;
>            else
> @@ -422,7 +422,7 @@ static int continue_buffered_image(struct vf_instance *vf)
>                deint(dmpi->planes[2], dmpi->stride[2], mpi->planes[2], mpi->stride[2],
>                    mpi->chroma_width, mpi->chroma_height, (i^!tff));
>            }
> -            ret |= vf_next_put_image(vf, dmpi, calc_pts(pts, i));
> +            ret |= vf_next_put_image(vf, dmpi, calc_pts(pts, i), MP_NOPTS_VALUE);
>            if (correct_pts)
>                break;
>            else
> @@ -448,7 +448,7 @@ static int continue_buffered_image(struct vf_instance *vf)
>                    mpi->chroma_width, mpi->chroma_height/2,
>                    dmpi->stride[2], mpi->stride[2]*2, (i^!tff));
>            }
> -            ret |= vf_next_put_image(vf, dmpi, calc_pts(pts, i));
> +            ret |= vf_next_put_image(vf, dmpi, calc_pts(pts, i), MP_NOPTS_VALUE);
>            if (correct_pts)
>                break;
>            else
> diff --git a/libmpcodecs/vf_tile.c b/libmpcodecs/vf_tile.c
> index 9ec037ef4..44f14c9fb 100644
> --- a/libmpcodecs/vf_tile.c
> +++ b/libmpcodecs/vf_tile.c
> @@ -107,7 +107,7 @@ static int config(struct vf_instance *vf,
> }
> 
> /* Filter handler */
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     mp_image_t        *dmpi;
>     struct vf_priv_s  *priv;
> @@ -184,7 +184,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>     }
>     else {
>         /* Skip the frame */
> diff --git a/libmpcodecs/vf_tinterlace.c b/libmpcodecs/vf_tinterlace.c
> index 8cd6ac89b..2fe3c2e7b 100644
> --- a/libmpcodecs/vf_tinterlace.c
> +++ b/libmpcodecs/vf_tinterlace.c
> @@ -37,7 +37,7 @@ struct vf_priv_s {
>     mp_image_t *dmpi;
> };
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts)
> {
>     int ret = 0;
>     mp_image_t *dmpi;
> @@ -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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         }
>         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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         break;
>     case 2:
>         if ((vf->priv->frame & 1) == 0)
> -            ret = vf_next_put_image(vf, mpi, MP_NOPTS_VALUE);
> +            ret = vf_next_put_image(vf, mpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         break;
>     case 3:
>         dmpi = vf_get_image(vf->next, mpi->imgfmt,
> @@ -116,7 +116,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
>                        dmpi->stride[2]*2, mpi->stride[2]);
>             }
>         }
> -        ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
> +        ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         break;
>     case 4:
>         // Interleave even lines (only) from Frame 'i' with odd
> @@ -166,7 +166,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, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>         }
>         break;
>     }
> diff --git a/libmpcodecs/vf_unsharp.c b/libmpcodecs/vf_unsharp.c
> index 56e85f473..12aec2390 100644
> --- a/libmpcodecs/vf_unsharp.c
> +++ b/libmpcodecs/vf_unsharp.c
> @@ -179,7 +179,7 @@ static void get_image( struct vf_instance *vf, mp_image_t *mpi ) {
>     mpi->flags |= MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts) {
> +static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts) {
>     mp_image_t *dmpi = mpi->priv;
>     mpi->priv = NULL;
> 
> @@ -202,7 +202,7 @@ static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts) {
>         __asm__ volatile ("sfence\n\t");
> #endif
> 
> -    return vf_next_put_image( vf, dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit( struct vf_instance *vf ) {
> diff --git a/libmpcodecs/vf_uspp.c b/libmpcodecs/vf_uspp.c
> index dd417009c..9f1709793 100644
> --- a/libmpcodecs/vf_uspp.c
> +++ b/libmpcodecs/vf_uspp.c
> @@ -275,7 +275,7 @@ static void get_image(struct vf_instance *vf, mp_image_t *mpi){
>     mpi->flags|=MP_IMGFLAG_DIRECT;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
> 
>     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
> @@ -307,7 +307,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
> #endif
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> static void uninit(struct vf_instance *vf){
> diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c
> index 6511460f7..ce5d51345 100644
> --- a/libmpcodecs/vf_vo.c
> +++ b/libmpcodecs/vf_vo.c
> @@ -34,6 +34,7 @@
> 
> struct vf_priv_s {
>     double pts;
> +    double endpts;
>     const vo_functions_t *vo;
> };
> #define video_out (vf->priv->vo)
> @@ -136,6 +137,11 @@ static int control(struct vf_instance *vf, int request, void* data)
>    *(double *)data = vf->priv->pts;
>    return CONTROL_TRUE;
>     }
> +    case VFCTRL_GET_ENDPTS:
> +    {
> +    *(double *)data = vf->priv->endpts;
> +    return CONTROL_TRUE;
> +    }
>     }
>     // return video_out->control(request,data);
>     return CONTROL_UNKNOWN;
> @@ -160,10 +166,11 @@ static void get_image(struct vf_instance *vf,
> }
> 
> static int put_image(struct vf_instance *vf,
> -        mp_image_t *mpi, double pts){
> +        mp_image_t *mpi, double pts, double endpts){
>   if(!vo_config_count) return 0; // vo not configured?
>   // record pts (potentially modified by filters) for main loop
>   vf->priv->pts = pts;
> +  vf->priv->endpts = endpts;
>   // first check, maybe the vo/vf plugin implements draw_image using mpi:
>   if(video_out->control(VOCTRL_DRAW_IMAGE,mpi)==VO_TRUE) return 1; // done.
>   // nope, fallback to old draw_frame/draw_slice:
> diff --git a/libmpcodecs/vf_yadif.c b/libmpcodecs/vf_yadif.c
> index ccd050f03..aeec5fcc9 100644
> --- a/libmpcodecs/vf_yadif.c
> +++ b/libmpcodecs/vf_yadif.c
> @@ -396,7 +396,7 @@ static int config(struct vf_instance *vf,
> 
> static int continue_buffered_image(struct vf_instance *vf);
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     int tff;
> 
>     if(vf->priv->parity < 0) {
> @@ -415,7 +415,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>     vf->priv->buffered_pts = pts;
> 
>     if(vf->priv->do_deinterlace == 0)
> -        return vf_next_put_image(vf, mpi, pts);
> +        return vf_next_put_image(vf, mpi, pts, endpts);
>     else if(vf->priv->do_deinterlace == 1){
>         vf->priv->do_deinterlace= 2;
>         return 0;
> @@ -443,7 +443,7 @@ static int continue_buffered_image(struct vf_instance *vf)
>         filter(vf->priv, dmpi->planes, dmpi->stride, mpi->w, mpi->h, i ^ tff ^ 1, tff);
>         if (correct_pts && i < (vf->priv->mode & 1))
>             vf_queue_frame(vf, continue_buffered_image);
> -        ret |= vf_next_put_image(vf, dmpi, pts /*FIXME*/);
> +        ret |= vf_next_put_image(vf, dmpi, pts /*FIXME*/, MP_NOPTS_VALUE);
>         if (correct_pts)
>             break;
>         if(i<(vf->priv->mode&1))
> diff --git a/libmpcodecs/vf_yuvcsp.c b/libmpcodecs/vf_yuvcsp.c
> index 102ce1453..efb3c7118 100644
> --- a/libmpcodecs/vf_yuvcsp.c
> +++ b/libmpcodecs/vf_yuvcsp.c
> @@ -48,7 +48,7 @@ static inline int clamp_c(int x){
>     return (x > 240) ? 240 : (x < 16) ? 16 : x;
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     int i,j;
>     uint8_t *y_in, *cb_in, *cr_in;
>     uint8_t *y_out, *cb_out, *cr_out;
> @@ -76,7 +76,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>             cr_out[i*vf->dmpi->stride[2]+j] = clamp_c(cr_in[i*mpi->stride[2]+j]);
>         }
> 
> -    return vf_next_put_image(vf,vf->dmpi, pts);
> +    return vf_next_put_image(vf, vf->dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_yvu9.c b/libmpcodecs/vf_yvu9.c
> index 1f74261cc..28f158d28 100644
> --- a/libmpcodecs/vf_yvu9.c
> +++ b/libmpcodecs/vf_yvu9.c
> @@ -45,7 +45,7 @@ static int config(struct vf_instance *vf,
>     return vf_next_config(vf,width,height,d_width,d_height,flags,IMGFMT_YV12);
> }
> 
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>     mp_image_t *dmpi;
>     int y,w,h;
> 
> @@ -75,7 +75,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> 
>     vf_clone_mpi_attributes(dmpi, mpi);
> 
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> //===========================================================================//
> diff --git a/libmpcodecs/vf_zrmjpeg.c b/libmpcodecs/vf_zrmjpeg.c
> index 6d3c7b2aa..ef5d5f00a 100644
> --- a/libmpcodecs/vf_zrmjpeg.c
> +++ b/libmpcodecs/vf_zrmjpeg.c
> @@ -817,7 +817,7 @@ static int config(struct vf_instance *vf, int width, int height, int d_width,
>  * \param mpi pointer to mp_image_t structure
>  * \param pts
>  */
> -static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
> +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
>    struct vf_priv_s *priv = vf->priv;
>    int size = 0;
>    int i;
> @@ -833,7 +833,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
>            MP_IMGTYPE_EXPORT, 0, mpi->w, mpi->h);
>    dmpi->planes[0] = (uint8_t*)priv->buf;
>    dmpi->planes[1] = (uint8_t*)size;
> -    return vf_next_put_image(vf,dmpi, pts);
> +    return vf_next_put_image(vf, dmpi, pts, endpts);
> }
> 
> /// query_format entrypoint for the ZRMJPEG vf filter
> diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
> index 29e434962..b70dae468 100644
> --- a/libmpdemux/demuxer.c
> +++ b/libmpdemux/demuxer.c
> @@ -886,14 +886,23 @@ int ds_get_packet(demux_stream_t *ds, unsigned char **start)
> 
> int ds_get_packet_pts(demux_stream_t *ds, unsigned char **start, double *pts)
> {
> +    double dummy;
> +    return ds_get_packet_pts_endpts(ds, start, pts, &dummy);
> +}
> +
> +int ds_get_packet_pts_endpts(demux_stream_t *ds, unsigned char **start, double *pts, double *endpts)
> +{
>     int len;
>     *pts = MP_NOPTS_VALUE;
> +    *endpts = MP_NOPTS_VALUE;
>     len = ds_get_packet(ds, start);
>     if (len < 0)
>         return len;
>     // Return pts unless this read starts from the middle of a packet
>     if (len == ds->buffer_pos)
>         *pts = ds->current->pts;
> +    if (len == ds->buffer_size)
> +        *endpts = ds->current->endpts;
>     return len;
> }
> 
> diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h
> index 516e663b5..eeb878bb8 100644
> --- a/libmpdemux/demuxer.h
> +++ b/libmpdemux/demuxer.h
> @@ -405,6 +405,7 @@ static inline int demux_getc(demux_stream_t *ds){
> void ds_free_packs(demux_stream_t *ds);
> int ds_get_packet(demux_stream_t *ds,unsigned char **start);
> int ds_get_packet_pts(demux_stream_t *ds, unsigned char **start, double *pts);
> +int ds_get_packet_pts_endpts(demux_stream_t *ds, unsigned char **start, double *pts, double *endpts);
> int ds_get_packet_sub(demux_stream_t *ds,unsigned char **start,
>                       double *pts, double *endpts);
> double ds_get_next_pts(demux_stream_t *ds);
> diff --git a/libmpdemux/stheader.h b/libmpdemux/stheader.h
> index 9060caa02..ddf180b05 100644
> --- a/libmpdemux/stheader.h
> +++ b/libmpdemux/stheader.h
> @@ -38,6 +38,7 @@
>   /* audio: last known pts value in output from decoder \
>    * video: predicted/interpolated PTS of the current frame */ \
>   double pts; \
> +  double endpts; \
>   /* codec-specific: */ \
>   void* context;   /* codec-specific stuff (usually HANDLE or struct pointer) */ \
>   char* lang; /* track language */ \
> @@ -102,6 +103,7 @@ typedef struct sh_video {
>   float next_frame_time;
>   double last_pts;
>   double buffered_pts[64];
> +  double buffered_endpts[64];
>   int num_buffered_pts;
>   // output format: (set by demuxer)
>   float fps;              // frames per second (set only if constant fps)
> diff --git a/mencoder.c b/mencoder.c
> index 0f6774c9e..9fc3ebe25 100644
> --- a/mencoder.c
> +++ b/mencoder.c
> @@ -463,9 +463,9 @@ static int slowseek(float end_pts, demux_stream_t *d_video,
> 
>         if (vfilter) {
>             int softskip = (vfilter->control(vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) == CONTROL_TRUE);
> -            void *decoded_frame = decode_video(sh_video, frame_data->start, frame_data->in_size, !softskip, MP_NOPTS_VALUE, NULL);
> +            void *decoded_frame = decode_video(sh_video, frame_data->start, frame_data->in_size, !softskip, MP_NOPTS_VALUE, MP_NOPTS_VALUE, NULL);
>        if (decoded_frame)
> -        filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE);
> +        filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
>        else if (frame_data->flush)
>        return 2;
>         }
> @@ -1504,7 +1504,7 @@ default:
>                      (!sh_video->vfilter ||
>                       ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) != CONTROL_TRUE);
>     void *decoded_frame = decode_video(sh_video,frame_data.start,frame_data.in_size,
> -                                       drop_frame, MP_NOPTS_VALUE, NULL);
> +                                       drop_frame, MP_NOPTS_VALUE, MP_NOPTS_VALUE, NULL);
>     if (frame_data.flush && !decoded_frame)
>         at_eof = 3;
>     if (did_seek && sh_video->pts != MP_NOPTS_VALUE) {
> @@ -1517,7 +1517,7 @@ default:
>     // sh_video->pts causes flickering with subtitles and complaints from MPEG-4
>     // encoder due to not being monotonic.
>     // If you change this please note the reason here!
> -    blit_frame = decoded_frame && filter_video(sh_video, decoded_frame, v_muxer_time + sub_offset);}
> +    blit_frame = decoded_frame && filter_video(sh_video, decoded_frame, v_muxer_time + sub_offset, MP_NOPTS_VALUE);}
>     v_muxer_time = adjusted_muxer_time(mux_v); // update after muxing
> 
>     if (sh_video->vf_initialized < 0) mencoder_exit(1, NULL);
> diff --git a/mplayer.c b/mplayer.c
> index 3bffb9792..c620eb5ed 100644
> --- a/mplayer.c
> +++ b/mplayer.c
> @@ -1777,6 +1777,7 @@ static int generate_video_frame(sh_video_t *sh_video, demux_stream_t *d_video)
>     int in_size;
>     int hit_eof = 0;
>     double pts;
> +    double endpts;
> 
>     while (1) {
>         int drop_frame = 0;
> @@ -1787,7 +1788,7 @@ static int generate_video_frame(sh_video_t *sh_video, demux_stream_t *d_video)
>         if (vf_output_queued_frame(sh_video->vfilter))
>             break;
>         current_module = "video_read_frame";
> -        in_size = ds_get_packet_pts(d_video, &start, &pts);
> +        in_size = ds_get_packet_pts_endpts(d_video, &start, &pts, &endpts);
>         if (in_size < 0) {
>             // try to extract last frames in case of decoder lag
>             in_size = 0;
> @@ -1799,13 +1800,13 @@ static int generate_video_frame(sh_video_t *sh_video, demux_stream_t *d_video)
>         if (in_size > max_framesize)
>             max_framesize = in_size;
>         current_module = "decode video";
> -        decoded_frame  = decode_video(sh_video, start, in_size, drop_frame, pts, NULL);
> +        decoded_frame  = decode_video(sh_video, start, in_size, drop_frame, pts, endpts, NULL);
>         if (decoded_frame) {
>             update_subtitles(sh_video, sh_video->pts, mpctx->d_sub, 0);
>             update_teletext(sh_video, mpctx->demuxer, 0);
>             update_osd_msg();
>             current_module = "filter video";
> -            if (filter_video(sh_video, decoded_frame, sh_video->pts))
> +            if (filter_video(sh_video, decoded_frame, sh_video->pts, sh_video->endpts))
>                 break;
>         } else if (drop_frame)
>             return -1;
> @@ -2491,7 +2492,7 @@ static double update_video(int *blit_frame)
>             // still frame has been reached, no need to decode
>             if ((in_size > 0 || flush) && !decoded_frame)
>             decoded_frame = decode_video(sh_video, start, in_size, drop_frame,
> -                                         sh_video->pts, &full_frame);
> +                                         sh_video->pts, sh_video->endpts, &full_frame);
> 
>             if (flush && !decoded_frame)
>                 return -1;
> @@ -2512,13 +2513,15 @@ static double update_video(int *blit_frame)
> 
>         current_module = "filter_video";
>         *blit_frame    = (decoded_frame && filter_video(sh_video, decoded_frame,
> -                                                        sh_video->pts));
> +                                                        sh_video->pts, sh_video->endpts));
>     } else {
>         int res = generate_video_frame(sh_video, mpctx->d_video);
>         if (!res)
>             return -1;
>         ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter,
>                                                       VFCTRL_GET_PTS, &sh_video->pts);
> +        ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter,
> +                                                      VFCTRL_GET_ENDPTS, &sh_video->endpts);
>         if (sh_video->pts == MP_NOPTS_VALUE) {
>             mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_PtsAfterFiltersMissing);
>             sh_video->pts = sh_video->last_pts;
> @@ -3795,7 +3798,7 @@ goto_enable_cache:
>                 update_osd_msg();
>             } else {
>                 int frame_time_remaining = 0;
> -                int blit_frame = 1;
> +                int blit_frame = mpctx->num_buffered_frames > 0;
>                 // skip timing after seek
>                 int skip_timing = mpctx->startup_decode_retry > 0;
> 
> @@ -3822,13 +3825,25 @@ goto_enable_cache:
>                         goto goto_next_file;
>                     }
>                     if (frame_time < 0) {
> +                        // try to figure out duration of last frame
> +                        if (correct_pts && mpctx->sh_video->endpts != MP_NOPTS_VALUE &&
> +                            mpctx->sh_video->pts != MP_NOPTS_VALUE &&
> +                            mpctx->sh_video->endpts > mpctx->sh_video->pts) {
> +                            frame_time = mpctx->sh_video->endpts - mpctx->sh_video->pts;
> +                        } else {
> +                            frame_time = mpctx->sh_video->frametime;
> +                        }
> +                        mpctx->sh_video->frametime = -1;
> +                        mpctx->sh_video->endpts = MP_NOPTS_VALUE;
> +                    }
> +                    if (frame_time < 0) {
>                         // if we have no more video, sleep some arbitrary time
>                         frame_time = 1.0 / 20.0;
>                         // Ensure vo_pts is updated so that ao_pcm will not hang.
>                         advance_timer(frame_time);
>                         // only stop playing when audio is at end as well
>                         if (!mpctx->sh_audio || (mpctx->d_audio->eof && !ds_fill_buffer(mpctx->d_audio)))
> -                            mpctx->eof = 1;
> +                            mpctx->eof = mpctx->time_frame <= 0;
>                     } else {
>                         // might return with !eof && !blit_frame if !correct_pts
>                         mpctx->num_buffered_frames += blit_frame;
> -- 
> 2.11.0
> 
> _______________________________________________
> MPlayer-dev-eng mailing list
> MPlayer-dev-eng at mplayerhq.hu
> https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng


More information about the MPlayer-dev-eng mailing list