1
mirror of https://github.com/mpv-player/mpv synced 2024-12-24 07:33:46 +01:00

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
This commit is contained in:
uau 2006-07-06 06:58:17 +00:00
parent 11ade8f86d
commit e2727ec797
15 changed files with 252 additions and 27 deletions

View File

@ -349,6 +349,8 @@ m_option_t mplayer_opts[]={
{"playlist", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL}, {"playlist", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL},
// a-v sync stuff: // a-v sync stuff:
{"correct-pts", &correct_pts, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"no-correct-pts", &correct_pts, CONF_TYPE_FLAG, 0, 1, 0, NULL},
{"noautosync", &autosync, CONF_TYPE_FLAG, 0, 0, -1, NULL}, {"noautosync", &autosync, CONF_TYPE_FLAG, 0, 0, -1, NULL},
{"autosync", &autosync, CONF_TYPE_INT, CONF_RANGE, 0, 10000, NULL}, {"autosync", &autosync, CONF_TYPE_INT, CONF_RANGE, 0, 10000, NULL},
// {"dapsync", &dapsync, CONF_TYPE_FLAG, 0, 0, 1, NULL}, // {"dapsync", &dapsync, CONF_TYPE_FLAG, 0, 0, 1, NULL},

View File

@ -137,6 +137,18 @@ void resync_video_stream(sh_video_t *sh_video)
if(mpvdec) mpvdec->control(sh_video, VDCTRL_RESYNC_STREAM, NULL); 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){ void uninit_video(sh_video_t *sh_video){
if(!sh_video->inited) return; if(!sh_video->inited) return;
mp_msg(MSGT_DECVIDEO,MSGL_V,MSGTR_UninitVideoStr,sh_video->codec->drv); mp_msg(MSGT_DECVIDEO,MSGL_V,MSGTR_UninitVideoStr,sh_video->codec->drv);
@ -311,6 +323,36 @@ unsigned int t2;
double tt; double tt;
int ret; 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) //if(!(sh_video->ds->flags&1) || sh_video->ds->pack_no<5)
mpi=mpvdec->decode(sh_video, start, in_size, drop_frame); 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(!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); //vo_draw_image(video_out,mpi);
vf=sh_video->vfilter; vf=sh_video->vfilter;
ret = vf->put_image(vf,mpi, pts); // apply video filters and call the leaf vo/ve ret = vf->put_image(vf,mpi, pts); // apply video filters and call the leaf vo/ve

View File

@ -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_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 int set_rectangle(sh_video_t *sh_video,int param,int value);
extern void resync_video_stream(sh_video_t *sh_video); 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; extern int divx_quality;

View File

@ -24,6 +24,7 @@ extern int vd_use_slices;
#define VDCTRL_SET_EQUALIZER 6 /* set color options (brightness,contrast etc) */ #define VDCTRL_SET_EQUALIZER 6 /* set color options (brightness,contrast etc) */
#define VDCTRL_GET_EQUALIZER 7 /* get color options (brightness,contrast etc) */ #define VDCTRL_GET_EQUALIZER 7 /* get color options (brightness,contrast etc) */
#define VDCTRL_RESYNC_STREAM 8 /* seeking */ #define VDCTRL_RESYNC_STREAM 8 /* seeking */
#define VDCTRL_QUERY_UNSEEN_FRAMES 9 /* current decoder lag */
// callbacks: // callbacks:
int mpcodecs_config_vo(sh_video_t *sh, int w, int h, unsigned int preferred_outfmt); int mpcodecs_config_vo(sh_video_t *sh, int w, int h, unsigned int preferred_outfmt);

View File

@ -188,7 +188,9 @@ static int control(sh_video_t *sh,int cmd,void* arg,...){
break; break;
case VDCTRL_RESYNC_STREAM: case VDCTRL_RESYNC_STREAM:
avcodec_flush_buffers(avctx); avcodec_flush_buffers(avctx);
return CONTROL_TRUE; return CONTROL_TRUE;
case VDCTRL_QUERY_UNSEEN_FRAMES:
return avctx->has_b_frames + 10;
} }
return CONTROL_UNKNOWN; return CONTROL_UNKNOWN;
} }

View File

@ -558,6 +558,38 @@ void vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src){
dst->qscale= src->qscale; 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 * \brief Video config() function wrapper
* *

View File

@ -43,6 +43,8 @@ typedef struct vf_instance_s {
void (*draw_slice)(struct vf_instance_s* vf, void (*draw_slice)(struct vf_instance_s* vf,
unsigned char** src, int* stride, int w,int h, int x, int y); unsigned char** src, int* stride, int w,int h, int x, int y);
void (*uninit)(struct vf_instance_s* vf); void (*uninit)(struct vf_instance_s* vf);
void (*continue_buffered_image)(struct vf_instance_s* vf);
// caps: // caps:
unsigned int default_caps; // used by default query_format() unsigned int default_caps; // used by default query_format()
unsigned int default_reqs; // used by default config() 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); 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_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: // default wrappers:
int vf_next_config(struct vf_instance_s* vf, int vf_next_config(struct vf_instance_s* vf,

View File

@ -15,6 +15,9 @@
struct vf_priv_s { struct vf_priv_s {
int mode; int mode;
int parity; 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) 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_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 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) 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; int ret=0;
mp_image_t *dmpi; mp_image_t *dmpi;
void (*qpel)(unsigned char *, unsigned char *, int, int, int, int, int); 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) { switch (vf->priv->mode) {
case 0: case 0:
for (i=0; i<2; i++) { for (; i<2; i++) {
dmpi = vf_get_image(vf->next, mpi->imgfmt, dmpi = vf_get_image(vf->next, mpi->imgfmt,
MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE, MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE,
mpi->width, mpi->height/2); 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[1] = 2*mpi->stride[1];
dmpi->stride[2] = 2*mpi->stride[2]; dmpi->stride[2] = 2*mpi->stride[2];
} }
ret |= vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); ret |= vf_next_put_image(vf, dmpi, pts);
if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); if (correct_pts)
break;
else
if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
} }
break; break;
case 1: case 1:
for (i=0; i<2; i++) { for (; i<2; i++) {
dmpi = vf_get_image(vf->next, mpi->imgfmt, dmpi = vf_get_image(vf->next, mpi->imgfmt,
MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
mpi->width, mpi->height); 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], deint(dmpi->planes[2], dmpi->stride[2], mpi->planes[2], mpi->stride[2],
mpi->chroma_width, mpi->chroma_height, (i^!tff)); mpi->chroma_width, mpi->chroma_height, (i^!tff));
} }
ret |= vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); ret |= vf_next_put_image(vf, dmpi, pts);
if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); if (correct_pts)
break;
else
if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
} }
break; break;
case 2: case 2:
case 3: case 3:
case 4: case 4:
for (i=0; i<2; i++) { for (; i<2; i++) {
dmpi = vf_get_image(vf->next, mpi->imgfmt, dmpi = vf_get_image(vf->next, mpi->imgfmt,
MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
mpi->width, mpi->height/2); 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, mpi->chroma_width, mpi->chroma_height/2,
dmpi->stride[2], mpi->stride[2]*2, (i^!tff)); dmpi->stride[2], mpi->stride[2]*2, (i^!tff));
} }
ret |= vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); ret |= vf_next_put_image(vf, dmpi, pts);
if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); if (correct_pts)
break;
else
if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
} }
break; break;
} }
vf->priv->buffered_i = 1;
return ret; return ret;
} }

View File

@ -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 */ 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, static int put_image(struct vf_instance_s* vf,
mp_image_t *mpi, double pts){ mp_image_t *mpi, double pts){
if(!vo_config_count) return 0; // vo not configured? 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: // 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. if(video_out->control(VOCTRL_DRAW_IMAGE,mpi)==VO_TRUE) return 1; // done.
// nope, fallback to old draw_frame/draw_slice: // nope, fallback to old draw_frame/draw_slice:

View File

@ -47,6 +47,10 @@
struct vf_priv_s { struct vf_priv_s {
int mode; int mode;
int parity; int parity;
int buffered_i;
int buffered_tff;
double buffered_pts;
mp_image_t *buffered_mpi;
int stride[3]; int stride[3];
uint8_t *ref[4][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); 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){ static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts){
mp_image_t *dmpi; int tff;
int ret=0;
int tff, i;
if(vf->priv->parity < 0) { if(vf->priv->parity < 0) {
if (mpi->fields & MP_IMGFIELD_ORDERED) 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); 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, dmpi=vf_get_image(vf->next,mpi->imgfmt,
MP_IMGTYPE_TEMP, MP_IMGTYPE_TEMP,
MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
mpi->width,mpi->height); mpi->width,mpi->height);
vf_clone_mpi_attributes(dmpi, mpi); vf_clone_mpi_attributes(dmpi, mpi);
filter(vf->priv, dmpi->planes, dmpi->stride, mpi->w, mpi->h, i ^ tff ^ 1, tff); 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*/);
if (correct_pts)
break;
if(i<(vf->priv->mode&1)) if(i<(vf->priv->mode&1))
vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL);
} }
vf->priv->buffered_i = 1;
return ret; return ret;
} }

View File

@ -1690,12 +1690,12 @@ demux_mkv_open_video (demuxer_t *demuxer, mkv_track_t *track)
else if (!strcmp(track->codec_id, MKV_V_MPEG1)) else if (!strcmp(track->codec_id, MKV_V_MPEG1))
{ {
bih->biCompression = mmioFOURCC('m', 'p', 'g', '1'); bih->biCompression = mmioFOURCC('m', 'p', 'g', '1');
track->reorder_timecodes = 1; track->reorder_timecodes = !correct_pts;
} }
else if (!strcmp(track->codec_id, MKV_V_MPEG2)) else if (!strcmp(track->codec_id, MKV_V_MPEG2))
{ {
bih->biCompression = mmioFOURCC('m', 'p', 'g', '2'); bih->biCompression = mmioFOURCC('m', 'p', 'g', '2');
track->reorder_timecodes = 1; track->reorder_timecodes = !correct_pts;
} }
else if (!strcmp(track->codec_id, MKV_V_MPEG4_AVC)) else if (!strcmp(track->codec_id, MKV_V_MPEG4_AVC))
{ {
@ -1706,7 +1706,7 @@ demux_mkv_open_video (demuxer_t *demuxer, mkv_track_t *track)
bih = (BITMAPINFOHEADER *) realloc (bih, bih->biSize); bih = (BITMAPINFOHEADER *) realloc (bih, bih->biSize);
memcpy (bih + 1, track->private_data, track->private_size); memcpy (bih + 1, track->private_data, track->private_size);
} }
track->reorder_timecodes = 1; track->reorder_timecodes = !correct_pts;
} }
else else
{ {

View File

@ -355,7 +355,7 @@ int ds_fill_buffer(demux_stream_t *ds){
ds->pos=p->pos; ds->pos=p->pos;
ds->dpos+=p->len; // !!! ds->dpos+=p->len; // !!!
++ds->pack_no; ++ds->pack_no;
if(p->pts){ if (p->pts != (correct_pts ? MP_NOPTS_VALUE : 0)) {
ds->pts=p->pts; ds->pts=p->pts;
ds->pts_bytes=0; ds->pts_bytes=0;
} }
@ -511,10 +511,11 @@ int ds_get_packet_pts(demux_stream_t *ds,unsigned char **start, double *pts)
*start = NULL; *start = NULL;
return -1; return -1;
} }
// Should use MP_NOPTS_VALUE for "unknown pts" in the packets too
if (ds->current->pts)
*pts = ds->current->pts;
} }
// Should use MP_NOPTS_VALUE for "unknown pts" in the packets too
// Return pts unless this read starts from the middle of a packet
if (!ds->buffer_pos && (correct_pts || ds->current->pts))
*pts = ds->current->pts;
len=ds->buffer_size-ds->buffer_pos; len=ds->buffer_size-ds->buffer_pos;
*start = &ds->buffer[ds->buffer_pos]; *start = &ds->buffer[ds->buffer_pos];
ds->buffer_pos+=len; ds->buffer_pos+=len;
@ -624,6 +625,8 @@ int get_demuxer_type_from_name(char *demuxer_name, int *force)
int extension_parsing=1; // 0=off 1=mixed (used only for unstable formats) int extension_parsing=1; // 0=off 1=mixed (used only for unstable formats)
int correct_pts=0;
/* /*
NOTE : Several demuxers may be opened at the same time so NOTE : Several demuxers may be opened at the same time so
demuxers should NEVER rely on an external var to enable them demuxers should NEVER rely on an external var to enable them

View File

@ -126,6 +126,8 @@ typedef struct demuxer_info_st {
struct demuxer_st; struct demuxer_st;
extern int correct_pts;
/** /**
* Demuxer description structure * Demuxer description structure
*/ */
@ -182,7 +184,9 @@ inline static demux_packet_t* new_demux_packet(int len){
demux_packet_t* dp=(demux_packet_t*)malloc(sizeof(demux_packet_t)); demux_packet_t* dp=(demux_packet_t*)malloc(sizeof(demux_packet_t));
dp->len=len; dp->len=len;
dp->next=NULL; dp->next=NULL;
dp->pts=0; // still using 0 by default in case there is some code that uses 0 for both
// unknown and a valid pts value
dp->pts=correct_pts ? MP_NOPTS_VALUE : 0;
dp->pos=0; dp->pos=0;
dp->flags=0; dp->flags=0;
dp->refcount=1; dp->refcount=1;

View File

@ -64,6 +64,8 @@ typedef struct {
// timing (mostly for mpeg): // timing (mostly for mpeg):
double pts; // predicted/interpolated PTS of the current frame double pts; // predicted/interpolated PTS of the current frame
double i_pts; // PTS for the _next_ I/P frame double i_pts; // PTS for the _next_ I/P frame
double buffered_pts[20];
int num_buffered_pts;
// output format: (set by demuxer) // output format: (set by demuxer)
float fps; // frames per second (set only if constant fps) float fps; // frames per second (set only if constant fps)
float frametime; // 1/fps float frametime; // 1/fps

View File

@ -2466,6 +2466,40 @@ static double playing_audio_pts(sh_audio_t *sh_audio, demux_stream_t *d_audio,
} }
static int generate_video_frame(sh_video_t *sh_video, demux_stream_t *d_video)
{
unsigned char *start;
int in_size;
int hit_eof=0;
double pts;
while (1) {
current_module = "decode video";
// XXX Time used in this call is not counted in any performance
// timer now
if (vf_output_queued_frame(sh_video->vfilter))
break;
current_module = "video_read_frame";
in_size = ds_get_packet_pts(d_video, &start, &pts);
if (in_size < 0) {
// try to extract last frames in case of decoder lag
in_size = 0;
pts = 1e300;
hit_eof = 1;
}
if (in_size > max_framesize)
max_framesize = in_size;
if (pts == MP_NOPTS_VALUE)
mp_msg(MSGT_CPLAYER, MSGL_ERR, "pts value from demuxer MISSING\n");
if (decode_video(sh_video, start, in_size, 0, pts))
break;
if (hit_eof)
return 0;
}
return 1;
}
int main(int argc,char* argv[]){ int main(int argc,char* argv[]){
@ -3505,9 +3539,11 @@ sh_video->video_out=video_out;
inited_flags|=INITED_VO; inited_flags|=INITED_VO;
} }
struct {double pts; vo_functions_t *vo;} vf_vo_data;
vf_vo_data.vo = video_out;
current_module="init_video_filters"; current_module="init_video_filters";
{ {
char* vf_arg[] = { "_oldargs_", (char*)video_out , NULL }; char* vf_arg[] = { "_oldargs_", (char*)&vf_vo_data , NULL };
sh_video->vfilter=(void*)vf_open_filter(NULL,"vo",vf_arg); sh_video->vfilter=(void*)vf_open_filter(NULL,"vo",vf_arg);
} }
#ifdef HAVE_MENU #ifdef HAVE_MENU
@ -3594,6 +3630,7 @@ fflush(stdout);
//float v_frame=0; // Video //float v_frame=0; // Video
float time_frame=0; // Timer float time_frame=0; // Timer
//float num_frames=0; // number of frames played //float num_frames=0; // number of frames played
double last_pts = MP_NOPTS_VALUE;
int grab_frames=0; int grab_frames=0;
int drop_frame=0; // current dropping status int drop_frame=0; // current dropping status
int dropped_frames=0; // how many frames dropped since last non-dropped frame int dropped_frames=0; // how many frames dropped since last non-dropped frame
@ -3768,7 +3805,7 @@ if(!sh_video) {
//-------------------- Decode a frame: ----------------------- //-------------------- Decode a frame: -----------------------
blit_frame = 0; // Don't blit if we hit EOF blit_frame = 0; // Don't blit if we hit EOF
vdecode_time=video_time_usage; vdecode_time=video_time_usage;
while(1) if (!correct_pts) while(1)
{ unsigned char* start=NULL; { unsigned char* start=NULL;
int in_size; int in_size;
// get it! // get it!
@ -3803,6 +3840,32 @@ if(!sh_video) {
blit_frame=decode_video(sh_video,start,in_size,drop_frame, MP_NOPTS_VALUE); blit_frame=decode_video(sh_video,start,in_size,drop_frame, MP_NOPTS_VALUE);
break; break;
} }
else while (1) {
if (!generate_video_frame(sh_video, d_video)) {
eof = 1;
break;
}
sh_video->pts = vf_vo_data.pts;
if (sh_video->pts == MP_NOPTS_VALUE) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, "pts after filters MISSING\n");
sh_video->pts == last_pts;
}
if (last_pts == MP_NOPTS_VALUE)
last_pts = sh_video->pts;
else if (last_pts >= sh_video->pts) {
last_pts = sh_video->pts;
mp_msg(MSGT_CPLAYER, MSGL_WARN, "pts value <= previous");
}
frame_time = sh_video->pts - last_pts;
last_pts = sh_video->pts;
sh_video->timer += frame_time;
time_frame += frame_time; // for nosound
if(sh_audio)
sh_audio->delay -= frame_time;
blit_frame = 1;
break;
}
vdecode_time=video_time_usage-vdecode_time; vdecode_time=video_time_usage-vdecode_time;
//------------------------ frame decoded. -------------------- //------------------------ frame decoded. --------------------
@ -4728,6 +4791,8 @@ if(rel_seek_secs || abs_seek_pos){
current_module="seek_video_reset"; current_module="seek_video_reset";
resync_video_stream(sh_video); resync_video_stream(sh_video);
if(vo_config_count) video_out->control(VOCTRL_RESET,NULL); if(vo_config_count) video_out->control(VOCTRL_RESET,NULL);
sh_video->num_buffered_pts = 0;
last_pts = MP_NOPTS_VALUE;
} }
if(sh_audio){ if(sh_audio){