aboutsummaryrefslogtreecommitdiffhomepage
path: root/libmpcodecs
diff options
context:
space:
mode:
authorGravatar uau <uau@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-07-06 06:58:17 +0000
committerGravatar uau <uau@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-07-06 06:58:17 +0000
commite2727ec797e19fb6d4d2d3338ce17dce976e0b28 (patch)
treed66f39217166121fab9751c1b271eb0734f68999 /libmpcodecs
parent11ade8f86d0d358e90737451983ed37075832e5e (diff)
Add a new video pts tracking mode, enabled by option -correct-pts.
This mode has the following differences: - Video timing is correct for streams with B frames, at least with some demuxers. - Video filters can modify frame timestamps and insert new frames, and removing frames is handled better than before. - Some things are known to break, it's not usable as the default yet. Things should work as before when the -correct-pts option is not used. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@18922 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpcodecs')
-rw-r--r--libmpcodecs/dec_video.c47
-rw-r--r--libmpcodecs/dec_video.h1
-rw-r--r--libmpcodecs/vd.h1
-rw-r--r--libmpcodecs/vd_ffmpeg.c4
-rw-r--r--libmpcodecs/vf.c32
-rw-r--r--libmpcodecs/vf.h4
-rw-r--r--libmpcodecs/vf_tfields.c51
-rw-r--r--libmpcodecs/vf_vo.c5
-rw-r--r--libmpcodecs/vf_yadif.c38
9 files changed, 166 insertions, 17 deletions
diff --git a/libmpcodecs/dec_video.c b/libmpcodecs/dec_video.c
index cba3693e46..b0c71897e1 100644
--- a/libmpcodecs/dec_video.c
+++ b/libmpcodecs/dec_video.c
@@ -137,6 +137,18 @@ void resync_video_stream(sh_video_t *sh_video)
if(mpvdec) mpvdec->control(sh_video, VDCTRL_RESYNC_STREAM, NULL);
}
+int get_current_video_decoder_lag(sh_video_t *sh_video)
+{
+ int ret;
+
+ if (!mpvdec)
+ return -1;
+ ret = mpvdec->control(sh_video, VDCTRL_QUERY_UNSEEN_FRAMES, NULL);
+ if (ret >= 10)
+ return ret-10;
+ return -1;
+}
+
void uninit_video(sh_video_t *sh_video){
if(!sh_video->inited) return;
mp_msg(MSGT_DECVIDEO,MSGL_V,MSGTR_UninitVideoStr,sh_video->codec->drv);
@@ -311,6 +323,36 @@ unsigned int t2;
double tt;
int ret;
+ if (correct_pts) {
+ int delay = get_current_video_decoder_lag(sh_video);
+ if (delay >= 0) {
+ if (delay > sh_video->num_buffered_pts)
+#if 0
+ // this is disabled because vd_ffmpeg reports the same lag
+ // after seek even when there are no buffered frames,
+ // leading to incorrect error messages
+ mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Not enough buffered pts\n");
+#else
+ ;
+#endif
+ else
+ sh_video->num_buffered_pts = delay;
+ }
+ if (sh_video->num_buffered_pts ==
+ sizeof(sh_video->buffered_pts)/sizeof(double))
+ mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Too many buffered pts\n");
+ else {
+ int i, j;
+ 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--)
+ sh_video->buffered_pts[j] = sh_video->buffered_pts[j-1];
+ sh_video->buffered_pts[i] = pts;
+ sh_video->num_buffered_pts++;
+ }
+ }
+
//if(!(sh_video->ds->flags&1) || sh_video->ds->pack_no<5)
mpi=mpvdec->decode(sh_video, start, in_size, drop_frame);
@@ -333,6 +375,11 @@ video_time_usage+=tt;
if(!mpi || drop_frame) return 0; // error / skipped frame
+ if (correct_pts) {
+ sh_video->num_buffered_pts--;
+ pts = sh_video->buffered_pts[sh_video->num_buffered_pts];
+ }
+
//vo_draw_image(video_out,mpi);
vf=sh_video->vfilter;
ret = vf->put_image(vf,mpi, pts); // apply video filters and call the leaf vo/ve
diff --git a/libmpcodecs/dec_video.h b/libmpcodecs/dec_video.h
index 449bec1162..08b861ccaa 100644
--- a/libmpcodecs/dec_video.h
+++ b/libmpcodecs/dec_video.h
@@ -19,5 +19,6 @@ extern int get_video_colors(sh_video_t *sh_video,char *item,int *value);
extern int set_video_colors(sh_video_t *sh_video,char *item,int value);
extern int set_rectangle(sh_video_t *sh_video,int param,int value);
extern void resync_video_stream(sh_video_t *sh_video);
+extern int get_current_video_decoder_lag(sh_video_t *sh_video);
extern int divx_quality;
diff --git a/libmpcodecs/vd.h b/libmpcodecs/vd.h
index 769a6c3a9b..d660ff84fd 100644
--- a/libmpcodecs/vd.h
+++ b/libmpcodecs/vd.h
@@ -24,6 +24,7 @@ extern int vd_use_slices;
#define VDCTRL_SET_EQUALIZER 6 /* set color options (brightness,contrast etc) */
#define VDCTRL_GET_EQUALIZER 7 /* get color options (brightness,contrast etc) */
#define VDCTRL_RESYNC_STREAM 8 /* seeking */
+#define VDCTRL_QUERY_UNSEEN_FRAMES 9 /* current decoder lag */
// callbacks:
int mpcodecs_config_vo(sh_video_t *sh, int w, int h, unsigned int preferred_outfmt);
diff --git a/libmpcodecs/vd_ffmpeg.c b/libmpcodecs/vd_ffmpeg.c
index ea2091f206..6e34ea351b 100644
--- a/libmpcodecs/vd_ffmpeg.c
+++ b/libmpcodecs/vd_ffmpeg.c
@@ -188,7 +188,9 @@ static int control(sh_video_t *sh,int cmd,void* arg,...){
break;
case VDCTRL_RESYNC_STREAM:
avcodec_flush_buffers(avctx);
- return CONTROL_TRUE;
+ return CONTROL_TRUE;
+ case VDCTRL_QUERY_UNSEEN_FRAMES:
+ return avctx->has_b_frames + 10;
}
return CONTROL_UNKNOWN;
}
diff --git a/libmpcodecs/vf.c b/libmpcodecs/vf.c
index 0b7014d17d..29fb5a2b55 100644
--- a/libmpcodecs/vf.c
+++ b/libmpcodecs/vf.c
@@ -558,6 +558,38 @@ void vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src){
dst->qscale= src->qscale;
}
}
+
+void vf_queue_frame(vf_instance_t *vf, int (*func)(vf_instance_t *))
+{
+ vf->continue_buffered_image = func;
+}
+
+// Output the next buffered image (if any) from the filter chain.
+// The queue could be kept as a simple stack/list instead avoiding the
+// looping here, but there's currently no good context variable where
+// that could be stored so this was easier to implement.
+
+int vf_output_queued_frame(vf_instance_t *vf)
+{
+ while (1) {
+ int ret;
+ vf_instance_t *current;
+ vf_instance_t *last=NULL;
+ int (*tmp)(vf_instance_t *);
+ for (current = vf; current; current = current->next)
+ if (current->continue_buffered_image)
+ last = current;
+ if (!last)
+ return 0;
+ tmp = last->continue_buffered_image;
+ last->continue_buffered_image = NULL;
+ ret = tmp(last);
+ if (ret)
+ return ret;
+ }
+}
+
+
/**
* \brief Video config() function wrapper
*
diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h
index 32a44d286b..0b3b209b17 100644
--- a/libmpcodecs/vf.h
+++ b/libmpcodecs/vf.h
@@ -43,6 +43,8 @@ typedef struct vf_instance_s {
void (*draw_slice)(struct vf_instance_s* vf,
unsigned char** src, int* stride, int w,int h, int x, int y);
void (*uninit)(struct vf_instance_s* vf);
+
+ void (*continue_buffered_image)(struct vf_instance_s* vf);
// caps:
unsigned int default_caps; // used by default query_format()
unsigned int default_reqs; // used by default config()
@@ -93,6 +95,8 @@ vf_instance_t* vf_open_encoder(vf_instance_t* next, char *name, char *args);
unsigned int vf_match_csp(vf_instance_t** vfp,unsigned int* list,unsigned int preferred);
void vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src);
+void vf_queue_frame(vf_instance_t *vf, int (*)(vf_instance_t *));
+int vf_output_queued_frame(vf_instance_t *vf);
// default wrappers:
int vf_next_config(struct vf_instance_s* vf,
diff --git a/libmpcodecs/vf_tfields.c b/libmpcodecs/vf_tfields.c
index 1b26fb89b9..b10b48ba10 100644
--- a/libmpcodecs/vf_tfields.c
+++ b/libmpcodecs/vf_tfields.c
@@ -15,6 +15,9 @@
struct vf_priv_s {
int mode;
int parity;
+ int buffered_i;
+ mp_image_t *buffered_mpi;
+ double buffered_pts;
};
static inline void *my_memcpy_pic(void * dst, void * src, int bytesPerLine, int height, int dstStride, int srcStride)
@@ -311,9 +314,27 @@ static void qpel_4tap_C(unsigned char *d, unsigned char *s, int w, int h, int ds
static void (*qpel_li)(unsigned char *d, unsigned char *s, int w, int h, int ds, int ss, int up);
static void (*qpel_4tap)(unsigned char *d, unsigned char *s, int w, int h, int ds, int ss, int up);
+static int continue_buffered_image(struct vf_instance_s *);
+extern int correct_pts;
+
static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts)
{
- int i;
+ vf->priv->buffered_mpi = mpi;
+ vf->priv->buffered_pts = pts;
+ vf->priv->buffered_i = 0;
+ return continue_buffered_image(vf);
+}
+
+static int continue_buffered_image(struct vf_instance_s *vf)
+{
+ int i=vf->priv->buffered_i;
+ double pts = vf->priv->buffered_pts;
+ mp_image_t *mpi = vf->priv->buffered_mpi;
+
+ if (i == 0)
+ vf_queue_frame(vf, continue_buffered_image);
+ pts += i * .02; // XXX not right
+
int ret=0;
mp_image_t *dmpi;
void (*qpel)(unsigned char *, unsigned char *, int, int, int, int, int);
@@ -344,7 +365,7 @@ static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts)
switch (vf->priv->mode) {
case 0:
- for (i=0; i<2; i++) {
+ for (; i<2; i++) {
dmpi = vf_get_image(vf->next, mpi->imgfmt,
MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE,
mpi->width, mpi->height/2);
@@ -356,12 +377,15 @@ static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts)
dmpi->stride[1] = 2*mpi->stride[1];
dmpi->stride[2] = 2*mpi->stride[2];
}
- ret |= vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
- if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
+ ret |= vf_next_put_image(vf, dmpi, pts);
+ if (correct_pts)
+ break;
+ else
+ if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
}
break;
case 1:
- for (i=0; i<2; i++) {
+ for (; i<2; i++) {
dmpi = vf_get_image(vf->next, mpi->imgfmt,
MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
mpi->width, mpi->height);
@@ -383,14 +407,17 @@ static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts)
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, MP_NOPTS_VALUE);
- if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
+ ret |= vf_next_put_image(vf, dmpi, pts);
+ if (correct_pts)
+ break;
+ else
+ if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
}
break;
case 2:
case 3:
case 4:
- for (i=0; i<2; i++) {
+ for (; i<2; i++) {
dmpi = vf_get_image(vf->next, mpi->imgfmt,
MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
mpi->width, mpi->height/2);
@@ -406,11 +433,15 @@ static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts)
mpi->chroma_width, mpi->chroma_height/2,
dmpi->stride[2], mpi->stride[2]*2, (i^!tff));
}
- ret |= vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
- if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
+ ret |= vf_next_put_image(vf, dmpi, pts);
+ if (correct_pts)
+ break;
+ else
+ if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
}
break;
}
+ vf->priv->buffered_i = 1;
return ret;
}
diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c
index d967b05a8b..571fbd7257 100644
--- a/libmpcodecs/vf_vo.c
+++ b/libmpcodecs/vf_vo.c
@@ -12,7 +12,8 @@
//===========================================================================//
-#define video_out ((vo_functions_t*)(vf->priv))
+struct priv_t {double pts; vo_functions_t *vo;};
+#define video_out (((struct priv_t *)(vf->priv))->vo)
static int query_format(struct vf_instance_s* vf, unsigned int fmt); /* forward declaration */
@@ -102,6 +103,8 @@ static void get_image(struct vf_instance_s* vf,
static int put_image(struct vf_instance_s* vf,
mp_image_t *mpi, double pts){
if(!vo_config_count) return 0; // vo not configured?
+ // record pts (potentially modified by filters) for main loop
+ ((struct priv_t *)vf->priv)->pts = pts;
// 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 01060f2892..2c2e387e45 100644
--- a/libmpcodecs/vf_yadif.c
+++ b/libmpcodecs/vf_yadif.c
@@ -47,6 +47,10 @@
struct vf_priv_s {
int mode;
int parity;
+ int buffered_i;
+ int buffered_tff;
+ double buffered_pts;
+ mp_image_t *buffered_mpi;
int stride[3];
uint8_t *ref[4][3];
};
@@ -150,10 +154,11 @@ static int config(struct vf_instance_s* vf,
return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
}
+static int continue_buffered_image(struct vf_instance_s *vf);
+extern int correct_pts;
+
static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts){
- mp_image_t *dmpi;
- int ret=0;
- int tff, i;
+ int tff;
if(vf->priv->parity < 0) {
if (mpi->fields & MP_IMGFIELD_ORDERED)
@@ -165,18 +170,41 @@ static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts){
store_ref(vf->priv, mpi->planes, mpi->stride, mpi->w, mpi->h);
- for(i=0; i<=(vf->priv->mode&1); i++){
+ vf->priv->buffered_mpi = mpi;
+ vf->priv->buffered_tff = tff;
+ vf->priv->buffered_i = 0;
+ vf->priv->buffered_pts = pts;
+
+ return continue_buffered_image(vf);
+}
+
+static int continue_buffered_image(struct vf_instance_s *vf)
+{
+ mp_image_t *mpi = vf->priv->buffered_mpi;
+ int tff = vf->priv->buffered_tff;
+ double pts = vf->priv->buffered_pts;
+ int i;
+ int ret=0;
+ mp_image_t *dmpi;
+
+ pts += vf->priv->buffered_i * .02; // XXX not right
+
+ for(i = vf->priv->buffered_i; i<=(vf->priv->mode&1); i++){
dmpi=vf_get_image(vf->next,mpi->imgfmt,
MP_IMGTYPE_TEMP,
MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
mpi->width,mpi->height);
vf_clone_mpi_attributes(dmpi, mpi);
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*/);
+ if (correct_pts)
+ break;
if(i<(vf->priv->mode&1))
vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
}
-
+ vf->priv->buffered_i = 1;
return ret;
}