summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2009-11-21 20:53:10 +0200
committerUoti Urpala <uau@glyph.nonexistent.invalid>2009-11-21 20:53:10 +0200
commit74b7dcc5f4d9be7293b78fced5ce888bb94c08dc (patch)
treee7b3c4da431f6e73ca858a4731f2883651bce697
parent4aff125b35984e7777d06edccdceeb28e531b907 (diff)
downloadmpv-74b7dcc5f4d9be7293b78fced5ce888bb94c08dc.tar.bz2
mpv-74b7dcc5f4d9be7293b78fced5ce888bb94c08dc.tar.xz
core: Add support for decoder reordering of pts values
Add a mode where libavcodec's reordered_opaque feature is used to associate container packet timestamps with decoded frames. This should improve behavior at least for MPEG files with interlaced h264; the previous code does not cope well with the libavformat demuxer producing two field packets with separate timestamps but the libavcodec h264 decoder only producing a single output frame for those two packets (so half the timestamps have no associated output frame). The current libavformat mpeg demuxer seems to finally work with interlaced h264 files and produce valid timestamps which are useful with a mode like this. By default MPlayer now selects between this new mode and the old one automatically based on the number of timestamp problems they cause; by default the new mode is used if both seem to work. The new option -pts-association-mode can be used to force a particular mode. If correct-pts mode is disabled this has no effect on timing. Also remove the "EXPERIMENTAL" marker from the manpage description of -correct-pts.
-rw-r--r--DOCS/man/en/mplayer.119
-rw-r--r--cfg-mplayer.h1
-rw-r--r--libmpcodecs/dec_video.c29
-rw-r--r--libmpcodecs/vd.h2
-rw-r--r--libmpcodecs/vd_ffmpeg.c30
-rw-r--r--libmpdemux/stheader.h7
-rw-r--r--mplayer.c31
-rw-r--r--options.h1
8 files changed, 111 insertions, 9 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index 083e7363fb..5a23c4d74c 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -803,8 +803,8 @@ xover, xv (see \-vo xv:ck), xvmc (see \-vo xv:ck) and directx video output
drivers.
.
.TP
-.B \-correct\-pts (EXPERIMENTAL)
-Switches MPlayer to an experimental mode where timestamps for video frames
+.B \-correct\-pts
+Switches MPlayer to a mode where timestamps for video frames
are calculated differently and video filters which add new frames or
modify timestamps of existing ones are supported.
The more accurate timestamps can be visible for example when playing
@@ -1044,6 +1044,21 @@ MPlayer will not load or search for video segments from other files,
and will also ignore any chapter order specified for the main file.
.
.TP
+.B \-pts\-association\-mode <mode number>
+Select the method used to determine which container packet timestamp
+corresponds to a particular output frame from the video decoder.
+.PD 0
+.RSs
+.IPs 0
+Try to pick a working mode from the ones below automatically (default)
+.IPs 1
+Use decoder reordering functionality.
+.IPs 2
+Maintain a buffer of unused pts values and use the lowest value for the frame.
+.RE
+.PD 1
+.
+.TP
.B \-rtc (RTC only)
Turns on usage of the Linux RTC (realtime clock \- /dev/\:rtc) as timing
mechanism.
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index efd69d6708..c00ad65214 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -312,6 +312,7 @@ const m_option_t mplayer_opts[]={
// a-v sync stuff:
OPT_FLAG_ON("correct-pts", user_correct_pts, 0),
OPT_FLAG_OFF("nocorrect-pts", user_correct_pts, 0),
+ OPT_INTRANGE("pts-association-mode", user_pts_assoc_mode, 0, 0, 2),
{"noautosync", &autosync, CONF_TYPE_FLAG, 0, 0, -1, NULL},
{"autosync", &autosync, CONF_TYPE_INT, CONF_RANGE, 0, 10000, NULL},
// {"dapsync", &dapsync, CONF_TYPE_FLAG, 0, 0, 1, NULL},
diff --git a/libmpcodecs/dec_video.c b/libmpcodecs/dec_video.c
index 0a258fabcb..e010715c4a 100644
--- a/libmpcodecs/dec_video.c
+++ b/libmpcodecs/dec_video.c
@@ -149,6 +149,8 @@ void resync_video_stream(sh_video_t *sh_video)
const struct vd_functions *vd = sh_video->vd_driver;
if (vd)
vd->control(sh_video, VDCTRL_RESYNC_STREAM, NULL);
+ sh_video->prev_codec_reordered_pts = MP_NOPTS_VALUE;
+ sh_video->prev_sorted_pts = MP_NOPTS_VALUE;
}
int get_current_video_decoder_lag(sh_video_t *sh_video)
@@ -307,6 +309,8 @@ static int init_video(sh_video_t *sh_video, char *codecname, char *vfm,
}
// Yeah! We got it!
sh_video->initialized = 1;
+ sh_video->prev_codec_reordered_pts = MP_NOPTS_VALUE;
+ sh_video->prev_sorted_pts = MP_NOPTS_VALUE;
return 1;
}
return 0;
@@ -411,7 +415,14 @@ void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
}
}
- mpi = sh_video->vd_driver->decode(sh_video, start, in_size, drop_frame);
+ if (sh_video->vd_driver->decode2) {
+ mpi = sh_video->vd_driver->decode2(sh_video, start, in_size,
+ drop_frame, &pts);
+ } else {
+ mpi = sh_video->vd_driver->decode(sh_video, start, in_size,
+ drop_frame);
+ pts = MP_NOPTS_VALUE;
+ }
//------------------------ frame decoded. --------------------
@@ -438,16 +449,28 @@ void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
else if (field_dominance == 1)
mpi->fields &= ~MP_IMGFIELD_TOP_FIRST;
+ double prevpts = sh_video->codec_reordered_pts;
+ sh_video->prev_codec_reordered_pts = prevpts;
+ sh_video->codec_reordered_pts = pts;
+ if (prevpts != MP_NOPTS_VALUE && pts <= prevpts
+ || pts == MP_NOPTS_VALUE)
+ sh_video->num_reordered_pts_problems++;
+ prevpts = sh_video->sorted_pts;
if (opts->correct_pts) {
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->sorted_pts =
+ sh_video->buffered_pts[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->sorted_pts = MP_NOPTS_VALUE;
}
}
+ pts = sh_video->sorted_pts;
+ if (prevpts != MP_NOPTS_VALUE && pts <= prevpts
+ || pts == MP_NOPTS_VALUE)
+ sh_video->num_sorted_pts_problems++;
return mpi;
}
diff --git a/libmpcodecs/vd.h b/libmpcodecs/vd.h
index df71970f7d..30e61c68b3 100644
--- a/libmpcodecs/vd.h
+++ b/libmpcodecs/vd.h
@@ -15,6 +15,8 @@ typedef struct vd_functions
void (*uninit)(sh_video_t *sh);
int (*control)(sh_video_t *sh,int cmd,void* arg, ...);
mp_image_t* (*decode)(sh_video_t *sh,void* data,int len,int flags);
+ struct mp_image *(*decode2)(struct sh_video *sh, void *data, int len,
+ int flags, double *reordered_pts);
} vd_functions_t;
// NULL terminated array of all drivers
diff --git a/libmpcodecs/vd_ffmpeg.c b/libmpcodecs/vd_ffmpeg.c
index 5e22bc6c81..eb53c6e830 100644
--- a/libmpcodecs/vd_ffmpeg.c
+++ b/libmpcodecs/vd_ffmpeg.c
@@ -14,7 +14,10 @@
#include "mpbswap.h"
#include "fmt-conversion.h"
-#include "vd_internal.h"
+#include "vd.h"
+#include "img_format.h"
+#include "libmpdemux/stheader.h"
+#include "codec-cfg.h"
static const vd_info_t info = {
"FFmpeg's libavcodec codec family",
@@ -24,8 +27,6 @@ static const vd_info_t info = {
"native codecs"
};
-LIBVD_EXTERN(ffmpeg)
-
#include "libavcodec/avcodec.h"
#if CONFIG_XVMC
@@ -62,6 +63,7 @@ static void draw_slice(struct AVCodecContext *s, const AVFrame *src,
static enum PixelFormat get_format(struct AVCodecContext *avctx,
const enum PixelFormat *pix_fmt);
+static void uninit(struct sh_video *sh);
const m_option_t lavc_decode_opts_conf[]={
OPT_INTRANGE("bug", lavc_param.workaround_bugs, 0, -1, 999999),
@@ -627,6 +629,13 @@ else
ctx->b_age=1;
}
pic->type= FF_BUFFER_TYPE_USER;
+
+ /* The libavcodec reordered_opaque functionality is implemented by
+ * a similar copy in avcodec_default_get_buffer() and without a
+ * workaround like this it'd stop working when a custom buffer
+ * callback is used.
+ */
+ pic->reordered_opaque = avctx->reordered_opaque;
return 0;
}
@@ -691,7 +700,9 @@ static void swap_palette(void *pal) {
}
// decode a frame
-static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){
+static struct mp_image *decode(struct sh_video *sh, void *data, int len,
+ int flags, double *reordered_pts)
+{
int got_picture=0;
int ret;
vd_ffmpeg_ctx *ctx = sh->context;
@@ -726,7 +737,10 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){
pkt.size = len;
// HACK: make PNGs decode normally instead of as CorePNG delta frames
pkt.flags = PKT_FLAG_KEY;
+ // The avcodec opaque field stupidly supports only int64_t type
+ *(double *)&avctx->reordered_opaque = *reordered_pts;
ret = avcodec_decode_video2(avctx, pic, &got_picture, &pkt);
+ *reordered_pts = *(double *)&pic->reordered_opaque;
dr1= ctx->do_dr1;
if(ret<0) mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Error while decoding frame!\n");
@@ -877,3 +891,11 @@ static enum PixelFormat get_format(struct AVCodecContext *avctx,
return selected_format;
}
#endif /* CONFIG_XVMC || CONFIG_VDPAU */
+
+const struct vd_functions mpcodecs_vd_ffmpeg = {
+ .info = &info,
+ .init = init,
+ .uninit = uninit,
+ .control = control,
+ .decode2 = decode
+};
diff --git a/libmpdemux/stheader.h b/libmpdemux/stheader.h
index 4ba42855cd..9b43f21dfd 100644
--- a/libmpdemux/stheader.h
+++ b/libmpdemux/stheader.h
@@ -93,6 +93,13 @@ typedef struct sh_video {
double last_pts;
double buffered_pts[20];
int num_buffered_pts;
+ double codec_reordered_pts;
+ double prev_codec_reordered_pts;
+ int num_reordered_pts_problems;
+ double sorted_pts;
+ double prev_sorted_pts;
+ int num_sorted_pts_problems;
+ int pts_assoc_mode;
// output format: (set by demuxer)
float fps; // frames per second (set only if constant fps)
float frametime; // 1/fps
diff --git a/mplayer.c b/mplayer.c
index fd29a7306b..4f79242c54 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -2328,6 +2328,36 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx,
return frame_time;
}
+static void determine_frame_pts(struct MPContext *mpctx)
+{
+ struct sh_video *sh_video = mpctx->sh_video;
+ struct MPOpts *opts = &mpctx->opts;
+
+ if (opts->user_pts_assoc_mode) {
+ sh_video->pts_assoc_mode = opts->user_pts_assoc_mode;
+ } else if (sh_video->pts_assoc_mode == 0) {
+ if (sh_video->codec_reordered_pts != MP_NOPTS_VALUE)
+ sh_video->pts_assoc_mode = 1;
+ else
+ sh_video->pts_assoc_mode = 2;
+ } else {
+ int probcount1 = sh_video->num_reordered_pts_problems;
+ int probcount2 = sh_video->num_sorted_pts_problems;
+ if (sh_video->pts_assoc_mode == 2) {
+ int tmp = probcount1;
+ probcount1 = probcount2;
+ probcount2 = tmp;
+ }
+ if (probcount1 >= probcount2 * 1.5 + 2) {
+ sh_video->pts_assoc_mode = 3 - sh_video->pts_assoc_mode;
+ mp_msg(MSGT_CPLAYER, MSGL_V, "Switching to pts association mode "
+ "%d.\n", sh_video->pts_assoc_mode);
+ }
+ }
+ sh_video->pts = sh_video->pts_assoc_mode == 1 ?
+ sh_video->codec_reordered_pts : sh_video->sorted_pts;
+}
+
static double update_video(struct MPContext *mpctx, int *blit_frame)
{
struct sh_video *sh_video = mpctx->sh_video;
@@ -2368,6 +2398,7 @@ static double update_video(struct MPContext *mpctx, int *blit_frame)
void *decoded_frame = decode_video(sh_video, packet, in_size,
framedrop_type, pts);
if (decoded_frame) {
+ determine_frame_pts(mpctx);
// These updates are done here for vf_expand OSD/subtitles
update_subtitles(mpctx, &mpctx->opts, sh_video, sh_video->pts,
mpctx->video_offset, mpctx->d_sub, 0);
diff --git a/options.h b/options.h
index 08a150bbdd..6ce7818e63 100644
--- a/options.h
+++ b/options.h
@@ -31,6 +31,7 @@ typedef struct MPOpts {
int ordered_chapters;
int correct_pts;
int user_correct_pts;
+ int user_pts_assoc_mode;
int key_fifo_size;
int doubleclick_time;
int audio_id;