2009-02-08 03:27:30 +00:00
|
|
|
/*
|
2015-04-13 07:36:54 +00:00
|
|
|
* This file is part of mpv.
|
2009-02-08 03:27:30 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or modify
|
2009-02-08 03:27:30 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2009-02-08 03:27:30 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
2015-04-13 07:36:54 +00:00
|
|
|
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2009-02-08 03:27:30 +00:00
|
|
|
*/
|
2001-02-24 20:28:24 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2009-09-17 14:47:43 +00:00
|
|
|
#include <assert.h>
|
2009-09-18 13:27:55 +00:00
|
|
|
#include <stdbool.h>
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
#include <pthread.h>
|
2015-10-08 20:06:15 +00:00
|
|
|
#include <math.h>
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2014-08-13 23:30:20 +00:00
|
|
|
#ifndef __MINGW32__
|
2001-02-24 20:28:24 +00:00
|
|
|
#include <unistd.h>
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
#include <poll.h>
|
2014-08-13 23:30:20 +00:00
|
|
|
#endif
|
2013-03-02 21:50:09 +00:00
|
|
|
|
|
|
|
#include "talloc.h"
|
2001-02-24 20:28:24 +00:00
|
|
|
|
|
|
|
#include "config.h"
|
2013-03-02 21:50:09 +00:00
|
|
|
#include "osdep/timer.h"
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
#include "osdep/threads.h"
|
|
|
|
#include "misc/dispatch.h"
|
|
|
|
#include "misc/rendezvous.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2014-08-29 10:09:04 +00:00
|
|
|
#include "misc/bstr.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "vo.h"
|
2007-02-17 20:58:55 +00:00
|
|
|
#include "aspect.h"
|
2013-12-17 00:23:09 +00:00
|
|
|
#include "input/input.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/m_config.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
|
|
|
#include "common/global.h"
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
#include "video/mp_image.h"
|
2013-11-24 11:58:06 +00:00
|
|
|
#include "sub/osd.h"
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
#include "osdep/io.h"
|
2014-10-19 21:32:34 +00:00
|
|
|
#include "osdep/threads.h"
|
2002-09-29 21:53:05 +00:00
|
|
|
|
2015-09-30 20:52:22 +00:00
|
|
|
extern const struct vo_driver video_out_x11;
|
2014-06-10 21:56:05 +00:00
|
|
|
extern const struct vo_driver video_out_vdpau;
|
|
|
|
extern const struct vo_driver video_out_xv;
|
|
|
|
extern const struct vo_driver video_out_opengl;
|
|
|
|
extern const struct vo_driver video_out_opengl_hq;
|
2014-12-09 16:47:02 +00:00
|
|
|
extern const struct vo_driver video_out_opengl_cb;
|
2014-06-10 21:56:05 +00:00
|
|
|
extern const struct vo_driver video_out_null;
|
|
|
|
extern const struct vo_driver video_out_image;
|
|
|
|
extern const struct vo_driver video_out_lavc;
|
|
|
|
extern const struct vo_driver video_out_caca;
|
2015-04-15 16:14:14 +00:00
|
|
|
extern const struct vo_driver video_out_drm;
|
2014-06-10 21:56:05 +00:00
|
|
|
extern const struct vo_driver video_out_direct3d;
|
|
|
|
extern const struct vo_driver video_out_direct3d_shaders;
|
|
|
|
extern const struct vo_driver video_out_sdl;
|
|
|
|
extern const struct vo_driver video_out_vaapi;
|
|
|
|
extern const struct vo_driver video_out_wayland;
|
2015-03-29 13:12:11 +00:00
|
|
|
extern const struct vo_driver video_out_rpi;
|
2008-04-03 03:25:41 +00:00
|
|
|
|
2014-06-10 21:56:05 +00:00
|
|
|
const struct vo_driver *const video_out_drivers[] =
|
2001-02-24 20:28:24 +00:00
|
|
|
{
|
2015-03-29 13:12:11 +00:00
|
|
|
#if HAVE_RPI
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_rpi,
|
2015-03-29 13:12:11 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_GL
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_opengl,
|
2013-02-06 21:29:21 +00:00
|
|
|
#endif
|
2014-08-17 00:54:50 +00:00
|
|
|
#if HAVE_VDPAU
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_vdpau,
|
2014-08-17 00:54:50 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_DIRECT3D
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_direct3d_shaders,
|
|
|
|
&video_out_direct3d,
|
2008-11-18 13:18:55 +00:00
|
|
|
#endif
|
2015-05-30 19:00:37 +00:00
|
|
|
#if HAVE_WAYLAND
|
|
|
|
&video_out_wayland,
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_XV
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_xv,
|
2009-09-18 21:25:36 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SDL2
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_sdl,
|
2012-12-28 07:07:14 +00:00
|
|
|
#endif
|
2015-10-02 02:19:12 +00:00
|
|
|
#if HAVE_VAAPI_X11
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_vaapi,
|
2015-09-30 20:52:22 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_X11
|
|
|
|
&video_out_x11,
|
2004-10-04 19:36:12 +00:00
|
|
|
#endif
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_null,
|
|
|
|
// should not be auto-selected
|
|
|
|
&video_out_image,
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_CACA
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_caca,
|
2013-02-06 21:29:21 +00:00
|
|
|
#endif
|
2015-04-15 16:14:14 +00:00
|
|
|
#if HAVE_DRM
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_drm,
|
2015-04-15 16:14:14 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_ENCODING
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_lavc,
|
2012-09-29 16:36:05 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_GL
|
2015-04-16 20:29:25 +00:00
|
|
|
&video_out_opengl_hq,
|
|
|
|
&video_out_opengl_cb,
|
2004-10-23 22:43:19 +00:00
|
|
|
#endif
|
2015-04-16 20:29:25 +00:00
|
|
|
NULL
|
2001-02-24 20:28:24 +00:00
|
|
|
};
|
2002-05-13 13:15:40 +00:00
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal {
|
|
|
|
pthread_t thread;
|
|
|
|
struct mp_dispatch_queue *dispatch;
|
|
|
|
|
|
|
|
// --- The following fields are protected by lock
|
|
|
|
pthread_mutex_t lock;
|
|
|
|
pthread_cond_t wakeup;
|
|
|
|
|
|
|
|
bool need_wakeup;
|
|
|
|
bool terminate;
|
|
|
|
|
|
|
|
int wakeup_pipe[2]; // used for VOs that use a unix FD for waiting
|
|
|
|
|
|
|
|
|
video: fix and simplify video format changes and last frame display
The previous commit broke these things, and fixing them is separate in
this commit in order to reduce the volume of changes.
Move the image queue from the VO to the playback core. The image queue
is a remnant of the old way how vdpau was implemented, and increasingly
became more and more an artifact. In the end, it did only one thing:
computing the duration of the current frame. This was done by taking the
PTS difference between the current and the future frame. We keep this,
but by moving it out of the VO, we don't have to special-case format
changes anymore. This simplifies the code a lot.
Since we need the queue to compute the duration only, a queue size
larger than 2 makes no sense, and we can hardcode that.
Also change how the last frame is handled. The last frame is a bit of a
problem, because video timing works by showing one frame after another,
which makes it a special case. Make the VO provide a function to notify
us when the frame is done, instead. The frame duration is used for that.
This is not perfect. For example, changing playback speed during the
last frame doesn't update the end time. Pausing will not stop the clock
that times the last frame. But I don't think this matters for such a
corner case.
2014-08-12 21:17:35 +00:00
|
|
|
bool hasframe;
|
2014-08-23 10:43:09 +00:00
|
|
|
bool hasframe_rendered;
|
2014-10-03 19:53:32 +00:00
|
|
|
bool request_redraw; // redraw request from player to VO
|
|
|
|
bool want_redraw; // redraw request from VO to player
|
2015-01-12 04:14:41 +00:00
|
|
|
bool send_reset; // send VOCTRL_RESET
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
bool paused;
|
2015-03-12 22:35:38 +00:00
|
|
|
int queued_events; // event mask for the user
|
|
|
|
int internal_events; // event mask for us
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2015-11-27 13:36:13 +00:00
|
|
|
int64_t nominal_vsync_interval;
|
2015-08-04 17:23:07 +00:00
|
|
|
|
2015-11-27 13:36:13 +00:00
|
|
|
int64_t vsync_interval;
|
2015-11-25 21:07:56 +00:00
|
|
|
int64_t *vsync_samples;
|
|
|
|
int num_vsync_samples;
|
2015-11-28 17:40:25 +00:00
|
|
|
int64_t num_total_vsync_samples;
|
2015-11-25 21:07:56 +00:00
|
|
|
int64_t prev_vsync;
|
2015-11-25 21:11:30 +00:00
|
|
|
int64_t base_vsync;
|
2015-11-25 21:11:58 +00:00
|
|
|
int drop_point;
|
2015-11-25 21:07:56 +00:00
|
|
|
double estimated_vsync_interval;
|
|
|
|
double estimated_vsync_jitter;
|
|
|
|
bool expecting_vsync;
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
int64_t flip_queue_offset; // queue flip events at most this much in advance
|
|
|
|
|
2015-11-13 21:41:41 +00:00
|
|
|
int64_t delayed_count;
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
int64_t drop_count;
|
|
|
|
bool dropped_frame; // the previous frame was dropped
|
2015-01-24 21:56:02 +00:00
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
struct vo_frame *current_frame; // last frame queued to the VO
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
int64_t wakeup_pts; // time at which to pull frame from decoder
|
|
|
|
|
|
|
|
bool rendering; // true if an image is being rendered
|
2015-07-01 17:24:28 +00:00
|
|
|
struct vo_frame *frame_queued; // should be drawn next
|
|
|
|
int req_frames; // VO's requested value of num_frames
|
2014-08-17 00:50:59 +00:00
|
|
|
|
2015-03-13 12:14:11 +00:00
|
|
|
double display_fps;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
};
|
|
|
|
|
2014-04-29 13:19:03 +00:00
|
|
|
static void forget_frames(struct vo *vo);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static void *vo_thread(void *ptr);
|
2014-04-29 13:19:03 +00:00
|
|
|
|
2013-07-21 19:17:48 +00:00
|
|
|
static bool get_desc(struct m_obj_desc *dst, int index)
|
|
|
|
{
|
|
|
|
if (index >= MP_ARRAY_SIZE(video_out_drivers) - 1)
|
|
|
|
return false;
|
|
|
|
const struct vo_driver *vo = video_out_drivers[index];
|
|
|
|
*dst = (struct m_obj_desc) {
|
2013-10-23 17:06:14 +00:00
|
|
|
.name = vo->name,
|
|
|
|
.description = vo->description,
|
2013-07-21 19:17:48 +00:00
|
|
|
.priv_size = vo->priv_size,
|
|
|
|
.priv_defaults = vo->priv_defaults,
|
|
|
|
.options = vo->options,
|
2015-03-10 16:17:15 +00:00
|
|
|
.hidden = vo->encode || !strcmp(vo->name, "opengl-cb"),
|
2013-07-21 19:17:48 +00:00
|
|
|
.p = vo,
|
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For the vo option
|
|
|
|
const struct m_obj_list vo_obj_list = {
|
|
|
|
.get_desc = get_desc,
|
|
|
|
.description = "video outputs",
|
|
|
|
.aliases = {
|
|
|
|
{"gl", "opengl"},
|
|
|
|
{"gl3", "opengl-hq"},
|
|
|
|
{0}
|
|
|
|
},
|
|
|
|
.allow_unknown_entries = true,
|
|
|
|
.allow_trailer = true,
|
|
|
|
};
|
2008-04-03 03:25:41 +00:00
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static void dispatch_wakeup_cb(void *ptr)
|
|
|
|
{
|
|
|
|
struct vo *vo = ptr;
|
|
|
|
vo_wakeup(vo);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does not include thread- and VO uninit.
|
|
|
|
static void dealloc_vo(struct vo *vo)
|
2014-04-22 19:06:23 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
forget_frames(vo); // implicitly synchronized
|
|
|
|
pthread_mutex_destroy(&vo->in->lock);
|
|
|
|
pthread_cond_destroy(&vo->in->wakeup);
|
|
|
|
for (int n = 0; n < 2; n++)
|
|
|
|
close(vo->in->wakeup_pipe[n]);
|
|
|
|
talloc_free(vo);
|
2014-04-22 19:06:23 +00:00
|
|
|
}
|
|
|
|
|
2014-12-19 17:37:16 +00:00
|
|
|
static struct vo *vo_create(bool probing, struct mpv_global *global,
|
2014-12-31 18:01:28 +00:00
|
|
|
struct vo_extra *ex, char *name, char **args)
|
2008-04-03 03:25:41 +00:00
|
|
|
{
|
2013-07-31 19:44:21 +00:00
|
|
|
struct mp_log *log = mp_log_new(NULL, global->log, "vo");
|
2013-07-21 19:17:48 +00:00
|
|
|
struct m_obj_desc desc;
|
|
|
|
if (!m_obj_list_find(&desc, &vo_obj_list, bstr0(name))) {
|
2013-12-21 20:49:13 +00:00
|
|
|
mp_msg(log, MSGL_ERR, "Video output %s not found!\n", name);
|
2013-07-31 19:44:21 +00:00
|
|
|
talloc_free(log);
|
2013-07-21 19:17:48 +00:00
|
|
|
return NULL;
|
|
|
|
};
|
|
|
|
struct vo *vo = talloc_ptrtype(NULL, vo);
|
|
|
|
*vo = (struct vo) {
|
2013-07-31 19:44:21 +00:00
|
|
|
.log = mp_log_new(vo, log, name),
|
2013-07-21 19:17:48 +00:00
|
|
|
.driver = desc.p,
|
2013-07-31 19:44:21 +00:00
|
|
|
.opts = &global->opts->vo,
|
2013-12-21 16:51:20 +00:00
|
|
|
.global = global,
|
2014-12-31 18:01:28 +00:00
|
|
|
.encode_lavc_ctx = ex->encode_lavc_ctx,
|
|
|
|
.input_ctx = ex->input_ctx,
|
|
|
|
.osd = ex->osd,
|
2013-07-21 19:17:48 +00:00
|
|
|
.event_fd = -1,
|
2014-01-11 17:44:27 +00:00
|
|
|
.monitor_par = 1,
|
2014-12-31 18:01:28 +00:00
|
|
|
.extra = *ex,
|
2014-12-19 17:37:16 +00:00
|
|
|
.probing = probing,
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
.in = talloc(vo, struct vo_internal),
|
2013-07-21 19:17:48 +00:00
|
|
|
};
|
2014-01-21 23:26:01 +00:00
|
|
|
talloc_steal(vo, log);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
*vo->in = (struct vo_internal) {
|
|
|
|
.dispatch = mp_dispatch_create(vo),
|
2015-07-01 17:24:28 +00:00
|
|
|
.req_frames = 1,
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
};
|
|
|
|
mp_make_wakeup_pipe(vo->in->wakeup_pipe);
|
|
|
|
mp_dispatch_set_wakeup_fn(vo->in->dispatch, dispatch_wakeup_cb, vo);
|
|
|
|
pthread_mutex_init(&vo->in->lock, NULL);
|
|
|
|
pthread_cond_init(&vo->in->wakeup, NULL);
|
|
|
|
|
2014-07-27 19:33:11 +00:00
|
|
|
mp_input_set_mouse_transform(vo->input_ctx, NULL, NULL);
|
2013-02-06 21:54:03 +00:00
|
|
|
if (vo->driver->encode != !!vo->encode_lavc_ctx)
|
2013-07-21 19:17:48 +00:00
|
|
|
goto error;
|
2013-12-21 18:45:42 +00:00
|
|
|
struct m_config *config = m_config_from_obj_desc(vo, vo->log, &desc);
|
2013-11-30 23:12:10 +00:00
|
|
|
if (m_config_apply_defaults(config, name, vo->opts->vo_defs) < 0)
|
|
|
|
goto error;
|
2013-07-22 20:52:42 +00:00
|
|
|
if (m_config_set_obj_params(config, args) < 0)
|
2013-07-21 19:17:48 +00:00
|
|
|
goto error;
|
2013-07-22 20:52:42 +00:00
|
|
|
vo->priv = config->optstruct;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
|
|
|
if (pthread_create(&vo->in->thread, NULL, vo_thread, vo))
|
|
|
|
goto error;
|
|
|
|
if (mp_rendezvous(vo, 0) < 0) { // init barrier
|
|
|
|
pthread_join(vo->in->thread, NULL);
|
2013-07-21 19:17:48 +00:00
|
|
|
goto error;
|
2014-04-22 19:06:23 +00:00
|
|
|
}
|
2013-07-21 19:17:48 +00:00
|
|
|
return vo;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2013-07-21 19:17:48 +00:00
|
|
|
error:
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
dealloc_vo(vo);
|
2013-07-21 19:17:48 +00:00
|
|
|
return NULL;
|
2008-04-03 03:25:41 +00:00
|
|
|
}
|
|
|
|
|
2014-12-31 18:01:28 +00:00
|
|
|
struct vo *init_best_video_out(struct mpv_global *global, struct vo_extra *ex)
|
2008-04-03 01:58:32 +00:00
|
|
|
{
|
2013-07-31 19:44:21 +00:00
|
|
|
struct m_obj_settings *vo_list = global->opts->vo.video_driver_list;
|
2002-09-29 21:53:05 +00:00
|
|
|
// first try the preferred drivers, with their optional subdevice param:
|
2013-07-21 19:17:48 +00:00
|
|
|
if (vo_list && vo_list[0].name) {
|
|
|
|
for (int n = 0; vo_list[n].name; n++) {
|
|
|
|
// Something like "-vo name," allows fallback to autoprobing.
|
|
|
|
if (strlen(vo_list[n].name) == 0)
|
|
|
|
goto autoprobe;
|
2014-12-19 17:37:16 +00:00
|
|
|
bool p = !!vo_list[n + 1].name;
|
2014-12-31 18:01:28 +00:00
|
|
|
struct vo *vo = vo_create(p, global, ex, vo_list[n].name,
|
|
|
|
vo_list[n].attribs);
|
2013-07-21 19:17:48 +00:00
|
|
|
if (vo)
|
|
|
|
return vo;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
autoprobe:
|
2002-09-29 21:53:05 +00:00
|
|
|
// now try the rest...
|
2013-07-21 19:17:48 +00:00
|
|
|
for (int i = 0; video_out_drivers[i]; i++) {
|
2015-01-21 18:39:58 +00:00
|
|
|
const struct vo_driver *driver = video_out_drivers[i];
|
|
|
|
if (driver == &video_out_null)
|
|
|
|
break;
|
|
|
|
struct vo *vo = vo_create(true, global, ex, (char *)driver->name, NULL);
|
2013-07-21 19:17:48 +00:00
|
|
|
if (vo)
|
|
|
|
return vo;
|
2002-09-29 21:53:05 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-04-22 19:03:52 +00:00
|
|
|
void vo_destroy(struct vo *vo)
|
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
mp_dispatch_lock(in->dispatch);
|
|
|
|
vo->in->terminate = true;
|
|
|
|
mp_dispatch_unlock(in->dispatch);
|
|
|
|
pthread_join(vo->in->thread, NULL);
|
|
|
|
dealloc_vo(vo);
|
2014-04-22 19:03:52 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 21:07:56 +00:00
|
|
|
// Drop timing information on discontinuities like seeking.
|
|
|
|
// Always called locked.
|
|
|
|
static void reset_vsync_timings(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
in->num_vsync_samples = 0;
|
2015-11-28 17:40:25 +00:00
|
|
|
in->num_total_vsync_samples = 0;
|
2015-11-25 21:11:58 +00:00
|
|
|
in->drop_point = 0;
|
2015-11-25 21:07:56 +00:00
|
|
|
in->estimated_vsync_interval = 0;
|
|
|
|
in->estimated_vsync_jitter = -1;
|
2015-11-25 21:11:30 +00:00
|
|
|
in->base_vsync = 0;
|
2015-11-25 21:07:56 +00:00
|
|
|
in->expecting_vsync = false;
|
|
|
|
}
|
|
|
|
|
2015-11-27 13:36:13 +00:00
|
|
|
static double vsync_stddef(struct vo *vo, int64_t ref_vsync)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
double jitter = 0;
|
|
|
|
for (int n = 0; n < in->num_vsync_samples; n++) {
|
|
|
|
double diff = in->vsync_samples[n] - ref_vsync;
|
|
|
|
jitter += diff * diff;
|
|
|
|
}
|
|
|
|
return sqrt(jitter / in->num_vsync_samples);
|
|
|
|
}
|
|
|
|
|
2015-11-29 16:49:08 +00:00
|
|
|
#define MAX_VSYNC_SAMPLES 200
|
|
|
|
|
|
|
|
// Check if we should switch to measured average display FPS if it seems
|
|
|
|
// "better" then the system-reported one. (Note that small differences are
|
|
|
|
// handled as drift instead.)
|
|
|
|
static void check_estimated_display_fps(struct vo *vo)
|
2015-11-25 21:07:56 +00:00
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
2015-11-27 20:56:29 +00:00
|
|
|
bool use_estimated = false;
|
2015-11-29 16:49:08 +00:00
|
|
|
if (in->num_total_vsync_samples >= MAX_VSYNC_SAMPLES * 2 &&
|
2015-11-27 13:36:13 +00:00
|
|
|
fabs((in->nominal_vsync_interval - in->estimated_vsync_interval))
|
|
|
|
>= 0.01 * in->nominal_vsync_interval &&
|
|
|
|
in->estimated_vsync_interval <= 1e6 / 20.0 &&
|
|
|
|
in->estimated_vsync_interval >= 1e6 / 99.0)
|
|
|
|
{
|
2015-11-29 16:41:01 +00:00
|
|
|
for (int n = 0; n < in->num_vsync_samples; n++) {
|
|
|
|
if (fabs(in->vsync_samples[n] - in->estimated_vsync_interval)
|
|
|
|
>= in->estimated_vsync_interval / 4)
|
|
|
|
goto done;
|
|
|
|
}
|
2015-11-27 13:36:13 +00:00
|
|
|
double mjitter = vsync_stddef(vo, in->estimated_vsync_interval);
|
|
|
|
double njitter = vsync_stddef(vo, in->nominal_vsync_interval);
|
2015-11-27 20:56:29 +00:00
|
|
|
if (mjitter * 1.01 < njitter)
|
|
|
|
use_estimated = true;
|
2015-11-29 16:41:01 +00:00
|
|
|
done: ;
|
2015-11-27 20:56:29 +00:00
|
|
|
}
|
2015-11-28 17:41:11 +00:00
|
|
|
if (use_estimated == (in->vsync_interval == in->nominal_vsync_interval)) {
|
|
|
|
if (use_estimated) {
|
|
|
|
MP_WARN(vo, "Reported display FPS seems incorrect.\n"
|
|
|
|
"Assuming a value closer to %.3f Hz.\n",
|
|
|
|
1e6 / in->estimated_vsync_interval);
|
|
|
|
} else {
|
|
|
|
MP_WARN(vo, "Switching back to assuming %.3f Hz.\n",
|
|
|
|
1e6 / in->nominal_vsync_interval);
|
|
|
|
}
|
2015-11-25 21:07:56 +00:00
|
|
|
}
|
2015-11-27 20:56:29 +00:00
|
|
|
in->vsync_interval = use_estimated ? (int64_t)in->estimated_vsync_interval
|
|
|
|
: in->nominal_vsync_interval;
|
2015-11-29 16:49:08 +00:00
|
|
|
}
|
2015-11-25 21:07:56 +00:00
|
|
|
|
2015-11-29 16:49:08 +00:00
|
|
|
// Attempt to detect vsyncs delayed/skipped by the driver. This tries to deal
|
|
|
|
// with strong jitter too, because some drivers have crap vsync timing.
|
|
|
|
static void vsync_skip_detection(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
2015-11-25 21:11:30 +00:00
|
|
|
|
2015-11-27 13:35:08 +00:00
|
|
|
int window = 4;
|
2015-11-29 16:49:08 +00:00
|
|
|
int64_t t_r = in->prev_vsync, t_e = in->base_vsync, diff = 0, desync_early = 0;
|
2015-11-27 13:35:08 +00:00
|
|
|
for (int n = 0; n < in->drop_point; n++) {
|
|
|
|
diff += t_r - t_e;
|
|
|
|
t_r -= in->vsync_samples[n];
|
|
|
|
t_e -= in->vsync_interval;
|
|
|
|
if (n == window + 1)
|
|
|
|
desync_early = diff / window;
|
|
|
|
}
|
|
|
|
int64_t desync = diff / in->num_vsync_samples;
|
|
|
|
if (in->drop_point > window * 2 &&
|
|
|
|
labs(desync - desync_early) >= in->vsync_interval * 3 / 4)
|
|
|
|
{
|
2015-11-25 21:11:30 +00:00
|
|
|
// Assume a drop. An underflow can technically speaking not be a drop
|
|
|
|
// (it's up to the driver what this is supposed to mean), but no reason
|
|
|
|
// to treat it differently.
|
2015-11-29 16:49:08 +00:00
|
|
|
in->base_vsync = in->prev_vsync;
|
2015-11-25 21:11:30 +00:00
|
|
|
in->delayed_count += 1;
|
2015-11-25 21:11:58 +00:00
|
|
|
in->drop_point = 0;
|
2015-11-25 21:11:30 +00:00
|
|
|
MP_STATS(vo, "vo-delayed");
|
|
|
|
}
|
2015-11-25 21:11:58 +00:00
|
|
|
if (in->drop_point > 10)
|
2015-11-29 16:49:08 +00:00
|
|
|
in->base_vsync += desync / 10; // smooth out drift
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always called locked.
|
|
|
|
static void update_vsync_timing_after_swap(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
|
|
|
int64_t now = mp_time_us();
|
|
|
|
|
|
|
|
if (!in->expecting_vsync) {
|
|
|
|
in->prev_vsync = now; // for normal system-time framedrop
|
|
|
|
reset_vsync_timings(vo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in->num_vsync_samples >= MAX_VSYNC_SAMPLES)
|
|
|
|
in->num_vsync_samples -= 1;
|
|
|
|
MP_TARRAY_INSERT_AT(in, in->vsync_samples, in->num_vsync_samples, 0,
|
|
|
|
now - in->prev_vsync);
|
|
|
|
in->drop_point = MPMIN(in->drop_point + 1, in->num_vsync_samples);
|
|
|
|
in->num_total_vsync_samples += 1;
|
|
|
|
if (in->base_vsync) {
|
|
|
|
in->base_vsync += in->vsync_interval;
|
|
|
|
} else {
|
|
|
|
in->base_vsync = now;
|
|
|
|
}
|
|
|
|
in->prev_vsync = now;
|
|
|
|
|
|
|
|
double avg = 0;
|
|
|
|
for (int n = 0; n < in->num_vsync_samples; n++)
|
|
|
|
avg += in->vsync_samples[n];
|
|
|
|
in->estimated_vsync_interval = avg / in->num_vsync_samples;
|
|
|
|
in->estimated_vsync_jitter =
|
|
|
|
vsync_stddef(vo, in->vsync_interval) / in->vsync_interval;
|
|
|
|
|
|
|
|
check_estimated_display_fps(vo);
|
|
|
|
vsync_skip_detection(vo);
|
|
|
|
|
|
|
|
MP_STATS(vo, "value %f jitter", in->estimated_vsync_jitter);
|
|
|
|
MP_STATS(vo, "value %f vsync-diff", in->vsync_samples[0] / 1e6);
|
2015-11-25 21:07:56 +00:00
|
|
|
}
|
|
|
|
|
2014-08-17 00:50:59 +00:00
|
|
|
// to be called from VO thread only
|
|
|
|
static void update_display_fps(struct vo *vo)
|
|
|
|
{
|
2015-03-12 22:35:38 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
if (in->internal_events & VO_EVENT_WIN_STATE) {
|
|
|
|
in->internal_events &= ~(unsigned)VO_EVENT_WIN_STATE;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
|
2015-03-13 12:14:11 +00:00
|
|
|
double display_fps = 0;
|
2015-03-12 22:35:38 +00:00
|
|
|
if (vo->global->opts->frame_drop_fps > 0) {
|
|
|
|
display_fps = vo->global->opts->frame_drop_fps;
|
|
|
|
} else {
|
|
|
|
vo->driver->control(vo, VOCTRL_GET_DISPLAY_FPS, &display_fps);
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-03-13 12:14:11 +00:00
|
|
|
|
2015-03-13 17:48:14 +00:00
|
|
|
if (in->display_fps != display_fps) {
|
|
|
|
in->display_fps = display_fps;
|
2015-11-25 21:11:14 +00:00
|
|
|
MP_VERBOSE(vo, "Assuming %f FPS for display sync.\n", display_fps);
|
2015-03-13 17:48:14 +00:00
|
|
|
|
|
|
|
// make sure to update the player
|
|
|
|
in->queued_events |= VO_EVENT_WIN_STATE;
|
|
|
|
mp_input_wakeup(vo->input_ctx);
|
|
|
|
}
|
2015-11-27 13:36:13 +00:00
|
|
|
|
|
|
|
in->nominal_vsync_interval = in->display_fps > 0 ? 1e6 / in->display_fps : 0;
|
|
|
|
in->vsync_interval = MPMAX(in->nominal_vsync_interval, 1);
|
2014-08-17 00:50:59 +00:00
|
|
|
}
|
2015-03-12 22:35:38 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
2014-08-17 00:50:59 +00:00
|
|
|
}
|
|
|
|
|
2014-04-21 20:53:51 +00:00
|
|
|
static void check_vo_caps(struct vo *vo)
|
|
|
|
{
|
|
|
|
int rot = vo->params->rotate;
|
|
|
|
if (rot) {
|
|
|
|
bool ok = rot % 90 ? false : (vo->driver->caps & VO_CAP_ROTATE90);
|
|
|
|
if (!ok) {
|
|
|
|
MP_WARN(vo, "Video is flagged as rotated by %d degrees, but the "
|
|
|
|
"video output does not support this.\n", rot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static void run_reconfig(void *p)
|
2008-04-03 01:58:32 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
void **pp = p;
|
|
|
|
struct vo *vo = pp[0];
|
|
|
|
struct mp_image_params *params = pp[1];
|
2015-10-03 16:20:16 +00:00
|
|
|
int *ret = pp[2];
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2015-01-24 21:56:02 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
2015-12-19 19:04:31 +00:00
|
|
|
mp_image_params_get_dsize(params, &vo->dwidth, &vo->dheight);
|
2007-02-17 20:58:55 +00:00
|
|
|
|
2014-01-21 23:26:01 +00:00
|
|
|
talloc_free(vo->params);
|
2014-01-24 20:22:25 +00:00
|
|
|
vo->params = talloc_memdup(vo, params, sizeof(*params));
|
2014-01-21 23:26:01 +00:00
|
|
|
|
2015-10-03 16:20:16 +00:00
|
|
|
*ret = vo->driver->reconfig(vo, vo->params);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
vo->config_ok = *ret >= 0;
|
2014-04-21 20:53:51 +00:00
|
|
|
if (vo->config_ok) {
|
|
|
|
check_vo_caps(vo);
|
|
|
|
} else {
|
2014-01-21 23:26:01 +00:00
|
|
|
talloc_free(vo->params);
|
|
|
|
vo->params = NULL;
|
|
|
|
}
|
2015-01-24 21:56:02 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-07-01 17:24:28 +00:00
|
|
|
talloc_free(in->current_frame);
|
|
|
|
in->current_frame = NULL;
|
2015-01-24 21:56:02 +00:00
|
|
|
forget_frames(vo);
|
2015-11-25 21:07:56 +00:00
|
|
|
reset_vsync_timings(vo);
|
2015-01-24 21:56:02 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
|
2014-08-17 00:50:59 +00:00
|
|
|
update_display_fps(vo);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
}
|
|
|
|
|
2015-10-03 16:20:16 +00:00
|
|
|
int vo_reconfig(struct vo *vo, struct mp_image_params *params)
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
{
|
|
|
|
int ret;
|
2015-10-03 16:20:16 +00:00
|
|
|
void *p[] = {vo, params, &ret};
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
mp_dispatch_run(vo->in->dispatch, run_reconfig, p);
|
2008-04-18 03:28:47 +00:00
|
|
|
return ret;
|
2007-02-17 20:58:55 +00:00
|
|
|
}
|
2002-09-29 21:53:05 +00:00
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static void run_control(void *p)
|
|
|
|
{
|
|
|
|
void **pp = p;
|
|
|
|
struct vo *vo = pp[0];
|
|
|
|
uint32_t request = *(int *)pp[1];
|
|
|
|
void *data = pp[2];
|
|
|
|
int ret = vo->driver->control(vo, request, data);
|
|
|
|
*(int *)pp[3] = ret;
|
|
|
|
}
|
|
|
|
|
2014-04-22 19:03:52 +00:00
|
|
|
int vo_control(struct vo *vo, uint32_t request, void *data)
|
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
int ret;
|
|
|
|
void *p[] = {vo, &request, data, &ret};
|
|
|
|
mp_dispatch_run(vo->in->dispatch, run_control, p);
|
|
|
|
return ret;
|
2014-04-22 19:03:52 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// must be called locked
|
2014-04-29 13:19:03 +00:00
|
|
|
static void forget_frames(struct vo *vo)
|
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
video: fix and simplify video format changes and last frame display
The previous commit broke these things, and fixing them is separate in
this commit in order to reduce the volume of changes.
Move the image queue from the VO to the playback core. The image queue
is a remnant of the old way how vdpau was implemented, and increasingly
became more and more an artifact. In the end, it did only one thing:
computing the duration of the current frame. This was done by taking the
PTS difference between the current and the future frame. We keep this,
but by moving it out of the VO, we don't have to special-case format
changes anymore. This simplifies the code a lot.
Since we need the queue to compute the duration only, a queue size
larger than 2 makes no sense, and we can hardcode that.
Also change how the last frame is handled. The last frame is a bit of a
problem, because video timing works by showing one frame after another,
which makes it a special case. Make the VO provide a function to notify
us when the frame is done, instead. The frame duration is used for that.
This is not perfect. For example, changing playback speed during the
last frame doesn't update the end time. Pausing will not stop the clock
that times the last frame. But I don't think this matters for such a
corner case.
2014-08-12 21:17:35 +00:00
|
|
|
in->hasframe = false;
|
2014-08-23 10:43:09 +00:00
|
|
|
in->hasframe_rendered = false;
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
in->drop_count = 0;
|
2015-11-13 21:41:41 +00:00
|
|
|
in->delayed_count = 0;
|
2015-07-01 17:24:28 +00:00
|
|
|
talloc_free(in->frame_queued);
|
|
|
|
in->frame_queued = NULL;
|
2015-01-24 21:56:02 +00:00
|
|
|
// don't unref current_frame; we always want to be able to redraw it
|
2015-08-10 16:43:25 +00:00
|
|
|
if (in->current_frame) {
|
|
|
|
in->current_frame->num_vsyncs = 0; // but reset future repeats
|
|
|
|
in->current_frame->display_synced = false; // mark discontinuity
|
|
|
|
}
|
2014-04-29 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
#ifndef __MINGW32__
|
|
|
|
static void wait_event_fd(struct vo *vo, int64_t until_time)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
|
|
|
struct pollfd fds[2] = {
|
|
|
|
{ .fd = vo->event_fd, .events = POLLIN },
|
|
|
|
{ .fd = in->wakeup_pipe[0], .events = POLLIN },
|
|
|
|
};
|
|
|
|
int64_t wait_us = until_time - mp_time_us();
|
|
|
|
int timeout_ms = MPCLAMP((wait_us + 500) / 1000, 0, 10000);
|
|
|
|
|
|
|
|
poll(fds, 2, timeout_ms);
|
|
|
|
|
|
|
|
if (fds[1].revents & POLLIN) {
|
|
|
|
char buf[100];
|
|
|
|
read(in->wakeup_pipe[0], buf, sizeof(buf)); // flush
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void wakeup_event_fd(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
|
|
|
write(in->wakeup_pipe[1], &(char){0}, 1);
|
2014-04-22 19:03:52 +00:00
|
|
|
}
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
#else
|
|
|
|
static void wait_event_fd(struct vo *vo, int64_t until_time){}
|
|
|
|
static void wakeup_event_fd(struct vo *vo){}
|
|
|
|
#endif
|
2014-04-22 19:03:52 +00:00
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// Called unlocked.
|
|
|
|
static void wait_vo(struct vo *vo, int64_t until_time)
|
2014-04-22 19:03:52 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
|
|
|
if (vo->event_fd >= 0) {
|
|
|
|
wait_event_fd(vo, until_time);
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
in->need_wakeup = false;
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
} else if (vo->driver->wait_events) {
|
|
|
|
vo->driver->wait_events(vo, until_time);
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
in->need_wakeup = false;
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
} else {
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-05-11 21:44:36 +00:00
|
|
|
if (!in->need_wakeup) {
|
|
|
|
struct timespec ts = mp_time_us_to_timespec(until_time);
|
|
|
|
pthread_cond_timedwait(&in->wakeup, &in->lock, &ts);
|
|
|
|
}
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
in->need_wakeup = false;
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
}
|
2014-04-22 19:03:52 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static void wakeup_locked(struct vo *vo)
|
2014-04-29 13:19:03 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
2015-05-12 20:31:22 +00:00
|
|
|
pthread_cond_broadcast(&in->wakeup);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
if (vo->event_fd >= 0)
|
|
|
|
wakeup_event_fd(vo);
|
|
|
|
if (vo->driver->wakeup)
|
|
|
|
vo->driver->wakeup(vo);
|
|
|
|
in->need_wakeup = true;
|
2014-04-29 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// Wakeup VO thread, and make it check for new events with VOCTRL_CHECK_EVENTS.
|
|
|
|
// To be used by threaded VO backends.
|
|
|
|
void vo_wakeup(struct vo *vo)
|
2014-04-22 19:03:52 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
wakeup_locked(vo);
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
}
|
|
|
|
|
video: fix and simplify video format changes and last frame display
The previous commit broke these things, and fixing them is separate in
this commit in order to reduce the volume of changes.
Move the image queue from the VO to the playback core. The image queue
is a remnant of the old way how vdpau was implemented, and increasingly
became more and more an artifact. In the end, it did only one thing:
computing the duration of the current frame. This was done by taking the
PTS difference between the current and the future frame. We keep this,
but by moving it out of the VO, we don't have to special-case format
changes anymore. This simplifies the code a lot.
Since we need the queue to compute the duration only, a queue size
larger than 2 makes no sense, and we can hardcode that.
Also change how the last frame is handled. The last frame is a bit of a
problem, because video timing works by showing one frame after another,
which makes it a special case. Make the VO provide a function to notify
us when the frame is done, instead. The frame duration is used for that.
This is not perfect. For example, changing playback speed during the
last frame doesn't update the end time. Pausing will not stop the clock
that times the last frame. But I don't think this matters for such a
corner case.
2014-08-12 21:17:35 +00:00
|
|
|
// Whether vo_queue_frame() can be called. If the VO is not ready yet, the
|
|
|
|
// function will return false, and the VO will call the wakeup callback once
|
|
|
|
// it's ready.
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// next_pts is the exact time when the next frame should be displayed. If the
|
|
|
|
// VO is ready, but the time is too "early", return false, and call the wakeup
|
|
|
|
// callback once the time is right.
|
2015-08-10 16:43:25 +00:00
|
|
|
// If next_pts is negative, disable any timing and draw the frame as fast as
|
|
|
|
// possible.
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
bool vo_is_ready_for_frame(struct vo *vo, int64_t next_pts)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-08-10 16:43:25 +00:00
|
|
|
bool r = vo->config_ok && !in->frame_queued &&
|
|
|
|
(!in->current_frame || in->current_frame->num_vsyncs < 1);
|
|
|
|
if (r && next_pts >= 0) {
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// Don't show the frame too early - it would basically freeze the
|
|
|
|
// display by disallowing OSD redrawing or VO interaction.
|
2014-12-10 16:00:18 +00:00
|
|
|
// Actually render the frame at earliest 50ms before target time.
|
|
|
|
next_pts -= (uint64_t)(0.050 * 1e6);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
next_pts -= in->flip_queue_offset;
|
|
|
|
int64_t now = mp_time_us();
|
|
|
|
if (next_pts > now)
|
|
|
|
r = false;
|
|
|
|
if (!in->wakeup_pts || next_pts < in->wakeup_pts) {
|
2015-11-25 21:10:55 +00:00
|
|
|
in->wakeup_pts = next_pts;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
wakeup_locked(vo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Direct the VO thread to put the currently queued image on the screen.
|
|
|
|
// vo_is_ready_for_frame() must have returned true before this call.
|
2015-07-01 17:24:28 +00:00
|
|
|
// Ownership of frame is handed to the vo.
|
|
|
|
void vo_queue_frame(struct vo *vo, struct vo_frame *frame)
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-08-10 16:43:25 +00:00
|
|
|
assert(vo->config_ok && !in->frame_queued &&
|
|
|
|
(!in->current_frame || in->current_frame->num_vsyncs < 1));
|
video: fix and simplify video format changes and last frame display
The previous commit broke these things, and fixing them is separate in
this commit in order to reduce the volume of changes.
Move the image queue from the VO to the playback core. The image queue
is a remnant of the old way how vdpau was implemented, and increasingly
became more and more an artifact. In the end, it did only one thing:
computing the duration of the current frame. This was done by taking the
PTS difference between the current and the future frame. We keep this,
but by moving it out of the VO, we don't have to special-case format
changes anymore. This simplifies the code a lot.
Since we need the queue to compute the duration only, a queue size
larger than 2 makes no sense, and we can hardcode that.
Also change how the last frame is handled. The last frame is a bit of a
problem, because video timing works by showing one frame after another,
which makes it a special case. Make the VO provide a function to notify
us when the frame is done, instead. The frame duration is used for that.
This is not perfect. For example, changing playback speed during the
last frame doesn't update the end time. Pausing will not stop the clock
that times the last frame. But I don't think this matters for such a
corner case.
2014-08-12 21:17:35 +00:00
|
|
|
in->hasframe = true;
|
2015-07-01 17:24:28 +00:00
|
|
|
in->frame_queued = frame;
|
2015-11-25 21:10:55 +00:00
|
|
|
in->wakeup_pts = frame->display_synced
|
2015-08-10 16:43:25 +00:00
|
|
|
? 0 : frame->pts + MPMAX(frame->duration, 0);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
wakeup_locked(vo);
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
2014-04-22 19:03:52 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// If a frame is currently being rendered (or queued), wait until it's done.
|
|
|
|
// Otherwise, return immediately.
|
|
|
|
void vo_wait_frame(struct vo *vo)
|
2014-04-22 19:03:52 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
while (in->frame_queued || in->rendering)
|
|
|
|
pthread_cond_wait(&in->wakeup, &in->lock);
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
}
|
|
|
|
|
2015-05-12 20:30:45 +00:00
|
|
|
// Wait until realtime is >= ts
|
|
|
|
// called without lock
|
|
|
|
static void wait_until(struct vo *vo, int64_t target)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
struct timespec ts = mp_time_us_to_timespec(target);
|
2015-05-12 20:31:22 +00:00
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
while (target > mp_time_us()) {
|
|
|
|
if (in->queued_events & VO_EVENT_LIVE_RESIZING)
|
|
|
|
break;
|
|
|
|
if (pthread_cond_timedwait(&in->wakeup, &in->lock, &ts))
|
2015-05-12 20:30:45 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-05-12 20:31:22 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
2015-05-12 20:30:45 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static bool render_frame(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
2015-07-01 17:24:28 +00:00
|
|
|
struct vo_frame *frame = NULL;
|
|
|
|
bool got_frame = false;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2014-08-17 00:50:59 +00:00
|
|
|
update_display_fps(vo);
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
if (in->frame_queued) {
|
|
|
|
talloc_free(in->current_frame);
|
|
|
|
in->current_frame = in->frame_queued;
|
|
|
|
in->frame_queued = NULL;
|
|
|
|
} else if (in->paused || !in->current_frame || !in->hasframe ||
|
2015-11-03 12:33:38 +00:00
|
|
|
(in->current_frame->display_synced && in->current_frame->num_vsyncs < 1) ||
|
2015-11-25 21:10:55 +00:00
|
|
|
!in->current_frame->display_synced)
|
2015-07-01 17:24:28 +00:00
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
frame = vo_frame_ref(in->current_frame);
|
|
|
|
assert(frame);
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
|
2015-08-10 16:43:25 +00:00
|
|
|
if (frame->display_synced) {
|
|
|
|
frame->pts = 0;
|
|
|
|
frame->duration = -1;
|
|
|
|
}
|
|
|
|
|
2015-11-27 20:52:06 +00:00
|
|
|
int64_t now = mp_time_us();
|
2015-07-01 17:24:28 +00:00
|
|
|
int64_t pts = frame->pts;
|
|
|
|
int64_t duration = frame->duration;
|
|
|
|
int64_t end_time = pts + duration;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2015-01-23 10:30:43 +00:00
|
|
|
// Time at which we should flip_page on the VO.
|
2015-08-10 16:43:25 +00:00
|
|
|
int64_t target = frame->display_synced ? 0 : pts - in->flip_queue_offset;
|
2015-01-23 10:30:43 +00:00
|
|
|
|
2015-06-07 18:57:44 +00:00
|
|
|
// "normal" strict drop threshold.
|
2015-11-27 20:52:06 +00:00
|
|
|
in->dropped_frame = duration >= 0 && end_time < now;
|
2015-06-07 18:57:44 +00:00
|
|
|
|
2015-08-10 16:43:25 +00:00
|
|
|
in->dropped_frame &= !frame->display_synced;
|
2014-09-20 13:14:43 +00:00
|
|
|
in->dropped_frame &= !(vo->driver->caps & VO_CAP_FRAMEDROP);
|
2015-01-20 08:11:14 +00:00
|
|
|
in->dropped_frame &= (vo->global->opts->frame_dropping & 1);
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
// Even if we're hopelessly behind, rather degrade to 10 FPS playback,
|
|
|
|
// instead of just freezing the display forever.
|
2015-11-27 20:52:06 +00:00
|
|
|
in->dropped_frame &= now - in->prev_vsync < 100 * 1000;
|
2015-07-01 17:24:28 +00:00
|
|
|
in->dropped_frame &= in->hasframe_rendered;
|
2015-01-23 10:30:43 +00:00
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
// Setup parameters for the next time this frame is drawn. ("frame" is the
|
|
|
|
// frame currently drawn, while in->current_frame is the potentially next.)
|
|
|
|
in->current_frame->repeat = true;
|
2015-10-29 21:17:43 +00:00
|
|
|
if (frame->display_synced) {
|
2015-11-27 21:04:44 +00:00
|
|
|
in->current_frame->vsync_offset += in->current_frame->vsync_interval;
|
2015-10-29 21:17:43 +00:00
|
|
|
in->dropped_frame |= in->current_frame->num_vsyncs < 1;
|
|
|
|
}
|
2015-08-10 16:43:25 +00:00
|
|
|
if (in->current_frame->num_vsyncs > 0)
|
|
|
|
in->current_frame->num_vsyncs -= 1;
|
2015-07-01 17:24:28 +00:00
|
|
|
|
2015-11-25 21:07:56 +00:00
|
|
|
in->expecting_vsync = in->current_frame->display_synced && !in->paused;
|
2015-11-27 20:50:59 +00:00
|
|
|
if (in->expecting_vsync && !in->num_vsync_samples) // first DS frame in a row
|
2015-11-27 20:52:06 +00:00
|
|
|
in->prev_vsync = now;
|
2015-11-25 21:07:56 +00:00
|
|
|
|
2015-08-01 20:16:52 +00:00
|
|
|
if (in->dropped_frame) {
|
|
|
|
in->drop_count += 1;
|
|
|
|
} else {
|
2015-02-07 20:14:43 +00:00
|
|
|
in->rendering = true;
|
2014-08-23 10:43:09 +00:00
|
|
|
in->hasframe_rendered = true;
|
2015-07-01 17:24:28 +00:00
|
|
|
int64_t prev_drop_count = vo->in->drop_count;
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
2014-09-16 20:06:27 +00:00
|
|
|
mp_input_wakeup(vo->input_ctx); // core can queue new video now
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2014-08-22 14:21:58 +00:00
|
|
|
MP_STATS(vo, "start video");
|
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
if (vo->driver->draw_frame) {
|
|
|
|
vo->driver->draw_frame(vo, frame);
|
2014-11-23 19:06:05 +00:00
|
|
|
} else {
|
2015-07-01 17:24:28 +00:00
|
|
|
vo->driver->draw_image(vo, mp_image_new_ref(frame->current));
|
2014-11-23 19:06:05 +00:00
|
|
|
}
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2015-05-12 20:30:45 +00:00
|
|
|
wait_until(vo, target);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
vo->driver->flip_page(vo);
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
|
2014-08-22 14:21:58 +00:00
|
|
|
MP_STATS(vo, "end video");
|
2015-08-10 16:43:25 +00:00
|
|
|
MP_STATS(vo, "video_end");
|
2014-08-22 14:21:58 +00:00
|
|
|
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-07-01 17:24:28 +00:00
|
|
|
in->dropped_frame = prev_drop_count < vo->in->drop_count;
|
2015-02-07 20:14:43 +00:00
|
|
|
in->rendering = false;
|
2015-08-10 16:43:25 +00:00
|
|
|
|
2015-11-25 21:07:56 +00:00
|
|
|
update_vsync_timing_after_swap(vo);
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
}
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
|
2015-08-01 20:16:52 +00:00
|
|
|
if (!in->dropped_frame) {
|
2015-02-07 20:14:43 +00:00
|
|
|
vo->want_redraw = false;
|
|
|
|
in->want_redraw = false;
|
|
|
|
in->request_redraw = false;
|
|
|
|
}
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
|
2015-05-12 20:31:22 +00:00
|
|
|
pthread_cond_broadcast(&in->wakeup); // for vo_wait_frame()
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
mp_input_wakeup(vo->input_ctx);
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
got_frame = true;
|
2015-01-23 10:30:43 +00:00
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
done:
|
|
|
|
talloc_free(frame);
|
2015-01-23 10:30:43 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
2015-11-03 19:47:15 +00:00
|
|
|
return got_frame || (in->frame_queued && in->frame_queued->display_synced);
|
2014-04-22 19:03:52 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static void do_redraw(struct vo *vo)
|
2014-06-15 18:46:57 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
vo->want_redraw = false;
|
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
if (!vo->config_ok)
|
|
|
|
return;
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
in->request_redraw = false;
|
2014-10-03 19:53:32 +00:00
|
|
|
in->want_redraw = false;
|
vo: generic redraw support
Usually, a VO must react to VOCTRL_REDRAW_FRAME in order to redraw the
current screen correctly if video is paused (this is done to update
OSD). But if it's not supported, we can just draw the current image
again in the generic vo.c code.
Unfortunately, this turned out pretty useless, because the VOs which
would benefit from this need to redraw even if there is no image, in
order to draw a black screen in --idle --force-window mode. The way
redrawing is handled in the X11 common code and in vo_x11 and vo_xv is
in the way, and I'm not sure what exactly vo_wayland requires. Other VOs
have a non-trivial implementation of VOCTRL_REDRAW_FRAME, which
(probably) makes redrawing slightly more efficient, e.g. by skipping
texture upload. So for now, no VO uses this new functionality, but since
it's trivial, commit it anyway.
The vo_driver->untimed case is for forcibly disabling redraw for vo_lavc
and vo_image always.
2015-01-24 22:28:38 +00:00
|
|
|
bool full_redraw = in->dropped_frame;
|
2015-07-01 17:24:28 +00:00
|
|
|
struct vo_frame *frame = NULL;
|
|
|
|
if (!vo->driver->untimed)
|
|
|
|
frame = vo_frame_ref(in->current_frame);
|
|
|
|
if (frame)
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
in->dropped_frame = false;
|
2015-07-01 17:24:28 +00:00
|
|
|
struct vo_frame dummy = {0};
|
|
|
|
if (!frame)
|
|
|
|
frame = &dummy;
|
|
|
|
frame->redraw = !full_redraw; // unconditionally redraw if it was dropped
|
|
|
|
frame->still = true;
|
2015-07-03 17:34:33 +00:00
|
|
|
frame->pts = 0;
|
|
|
|
frame->duration = -1;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
if (vo->driver->draw_frame) {
|
|
|
|
vo->driver->draw_frame(vo, frame);
|
2015-08-03 18:21:10 +00:00
|
|
|
} else if ((full_redraw || vo->driver->control(vo, VOCTRL_REDRAW_FRAME, NULL) < 1)
|
2015-07-01 17:24:28 +00:00
|
|
|
&& frame->current)
|
|
|
|
{
|
|
|
|
vo->driver->draw_image(vo, mp_image_new_ref(frame->current));
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
}
|
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
vo->driver->flip_page(vo);
|
|
|
|
|
|
|
|
if (frame != &dummy)
|
|
|
|
talloc_free(frame);
|
2014-06-15 18:46:57 +00:00
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
static void *vo_thread(void *ptr)
|
2014-04-22 19:03:52 +00:00
|
|
|
{
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
struct vo *vo = ptr;
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
|
2014-10-19 21:32:34 +00:00
|
|
|
mpthread_set_name("vo");
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
int r = vo->driver->preinit(vo) ? -1 : 0;
|
|
|
|
mp_rendezvous(vo, r); // init barrier
|
|
|
|
if (r < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2015-03-13 12:14:11 +00:00
|
|
|
update_display_fps(vo);
|
2015-04-16 20:31:09 +00:00
|
|
|
vo_event(vo, VO_EVENT_WIN_STATE);
|
2015-03-13 12:14:11 +00:00
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
while (1) {
|
|
|
|
mp_dispatch_queue_process(vo->in->dispatch, 0);
|
|
|
|
if (in->terminate)
|
|
|
|
break;
|
|
|
|
vo->driver->control(vo, VOCTRL_CHECK_EVENTS, NULL);
|
2015-11-03 19:47:15 +00:00
|
|
|
bool working = render_frame(vo);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
int64_t now = mp_time_us();
|
2015-11-03 19:47:15 +00:00
|
|
|
int64_t wait_until = now + (working ? 0 : (int64_t)1e9);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
if (in->wakeup_pts) {
|
|
|
|
if (in->wakeup_pts > now) {
|
|
|
|
wait_until = MPMIN(wait_until, in->wakeup_pts);
|
|
|
|
} else {
|
|
|
|
in->wakeup_pts = 0;
|
|
|
|
mp_input_wakeup(vo->input_ctx);
|
|
|
|
}
|
|
|
|
}
|
2014-10-03 19:53:32 +00:00
|
|
|
if (vo->want_redraw && !in->want_redraw) {
|
|
|
|
in->want_redraw = true;
|
|
|
|
mp_input_wakeup(vo->input_ctx);
|
|
|
|
}
|
|
|
|
bool redraw = in->request_redraw;
|
2015-01-12 04:14:41 +00:00
|
|
|
bool send_reset = in->send_reset;
|
|
|
|
in->send_reset = false;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
2015-01-12 04:14:41 +00:00
|
|
|
if (send_reset)
|
|
|
|
vo->driver->control(vo, VOCTRL_RESET, NULL);
|
2014-10-03 19:53:32 +00:00
|
|
|
if (wait_until > now && redraw) {
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
do_redraw(vo); // now is a good time
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
wait_vo(vo, wait_until);
|
|
|
|
}
|
2015-07-01 17:24:28 +00:00
|
|
|
forget_frames(vo); // implicitly synchronized
|
|
|
|
talloc_free(in->current_frame);
|
|
|
|
in->current_frame = NULL;
|
2015-07-04 15:27:13 +00:00
|
|
|
vo->driver->uninit(vo);
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
void vo_set_paused(struct vo *vo, bool paused)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
if (in->paused != paused) {
|
2014-09-21 08:06:06 +00:00
|
|
|
in->paused = paused;
|
2015-11-15 12:17:54 +00:00
|
|
|
if (in->paused && in->dropped_frame)
|
|
|
|
in->request_redraw = true;
|
2015-11-25 21:07:56 +00:00
|
|
|
reset_vsync_timings(vo);
|
video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.
On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).
This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.
On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.
"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 21:33:33 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
vo_control(vo, paused ? VOCTRL_PAUSE : VOCTRL_RESUME, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t vo_get_drop_count(struct vo *vo)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&vo->in->lock);
|
|
|
|
int64_t r = vo->in->drop_count;
|
|
|
|
pthread_mutex_unlock(&vo->in->lock);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-01-08 19:16:49 +00:00
|
|
|
void vo_increment_drop_count(struct vo *vo, int64_t n)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&vo->in->lock);
|
|
|
|
vo->in->drop_count += n;
|
|
|
|
pthread_mutex_unlock(&vo->in->lock);
|
|
|
|
}
|
|
|
|
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// Make the VO redraw the OSD at some point in the future.
|
|
|
|
void vo_redraw(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
if (!in->request_redraw) {
|
|
|
|
in->request_redraw = true;
|
|
|
|
wakeup_locked(vo);
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
2014-04-22 19:03:52 +00:00
|
|
|
}
|
|
|
|
|
2014-10-03 19:53:32 +00:00
|
|
|
bool vo_want_redraw(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
bool r = in->want_redraw;
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-04-22 19:03:52 +00:00
|
|
|
void vo_seek_reset(struct vo *vo)
|
|
|
|
{
|
2015-11-14 20:44:59 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2014-04-29 13:19:03 +00:00
|
|
|
forget_frames(vo);
|
2015-11-25 21:07:56 +00:00
|
|
|
reset_vsync_timings(vo);
|
2015-11-14 20:44:59 +00:00
|
|
|
in->send_reset = true;
|
2015-01-12 04:14:41 +00:00
|
|
|
wakeup_locked(vo);
|
2015-11-14 20:44:59 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
2008-12-20 11:52:11 +00:00
|
|
|
}
|
|
|
|
|
video: fix and simplify video format changes and last frame display
The previous commit broke these things, and fixing them is separate in
this commit in order to reduce the volume of changes.
Move the image queue from the VO to the playback core. The image queue
is a remnant of the old way how vdpau was implemented, and increasingly
became more and more an artifact. In the end, it did only one thing:
computing the duration of the current frame. This was done by taking the
PTS difference between the current and the future frame. We keep this,
but by moving it out of the VO, we don't have to special-case format
changes anymore. This simplifies the code a lot.
Since we need the queue to compute the duration only, a queue size
larger than 2 makes no sense, and we can hardcode that.
Also change how the last frame is handled. The last frame is a bit of a
problem, because video timing works by showing one frame after another,
which makes it a special case. Make the VO provide a function to notify
us when the frame is done, instead. The frame duration is used for that.
This is not perfect. For example, changing playback speed during the
last frame doesn't update the end time. Pausing will not stop the clock
that times the last frame. But I don't think this matters for such a
corner case.
2014-08-12 21:17:35 +00:00
|
|
|
// Return true if there is still a frame being displayed (or queued).
|
|
|
|
// If this returns true, a wakeup some time in the future is guaranteed.
|
|
|
|
bool vo_still_displaying(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&vo->in->lock);
|
|
|
|
int64_t now = mp_time_us();
|
2015-07-01 17:24:28 +00:00
|
|
|
int64_t frame_end = 0;
|
2015-08-10 16:43:25 +00:00
|
|
|
if (in->current_frame) {
|
2015-07-01 17:24:28 +00:00
|
|
|
frame_end = in->current_frame->pts + MPMAX(in->current_frame->duration, 0);
|
2015-08-12 08:46:29 +00:00
|
|
|
if (in->current_frame->display_synced)
|
|
|
|
frame_end = in->current_frame->num_vsyncs > 0 ? INT64_MAX : 0;
|
2015-08-10 16:43:25 +00:00
|
|
|
}
|
video: fix and simplify video format changes and last frame display
The previous commit broke these things, and fixing them is separate in
this commit in order to reduce the volume of changes.
Move the image queue from the VO to the playback core. The image queue
is a remnant of the old way how vdpau was implemented, and increasingly
became more and more an artifact. In the end, it did only one thing:
computing the duration of the current frame. This was done by taking the
PTS difference between the current and the future frame. We keep this,
but by moving it out of the VO, we don't have to special-case format
changes anymore. This simplifies the code a lot.
Since we need the queue to compute the duration only, a queue size
larger than 2 makes no sense, and we can hardcode that.
Also change how the last frame is handled. The last frame is a bit of a
problem, because video timing works by showing one frame after another,
which makes it a special case. Make the VO provide a function to notify
us when the frame is done, instead. The frame duration is used for that.
This is not perfect. For example, changing playback speed during the
last frame doesn't update the end time. Pausing will not stop the clock
that times the last frame. But I don't think this matters for such a
corner case.
2014-08-12 21:17:35 +00:00
|
|
|
bool working = now < frame_end || in->rendering || in->frame_queued;
|
|
|
|
pthread_mutex_unlock(&vo->in->lock);
|
|
|
|
return working && in->hasframe;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Whether at least 1 frame was queued or rendered since last seek or reconfig.
|
|
|
|
bool vo_has_frame(struct vo *vo)
|
|
|
|
{
|
|
|
|
return vo->in->hasframe;
|
|
|
|
}
|
|
|
|
|
2014-08-20 19:35:45 +00:00
|
|
|
static void run_query_format(void *p)
|
|
|
|
{
|
|
|
|
void **pp = p;
|
|
|
|
struct vo *vo = pp[0];
|
2015-01-03 16:23:01 +00:00
|
|
|
uint8_t *list = pp[1];
|
|
|
|
for (int format = IMGFMT_START; format < IMGFMT_END; format++)
|
|
|
|
list[format - IMGFMT_START] = vo->driver->query_format(vo, format);
|
2014-08-20 19:35:45 +00:00
|
|
|
}
|
|
|
|
|
2015-01-03 16:23:01 +00:00
|
|
|
// For each item in the list (allocated as uint8_t[IMGFMT_END - IMGFMT_START]),
|
|
|
|
// set the supported format flags.
|
|
|
|
void vo_query_formats(struct vo *vo, uint8_t *list)
|
2014-08-20 19:35:45 +00:00
|
|
|
{
|
2015-01-03 16:23:01 +00:00
|
|
|
void *p[] = {vo, list};
|
2014-08-20 19:35:45 +00:00
|
|
|
mp_dispatch_run(vo->in->dispatch, run_query_format, p);
|
|
|
|
}
|
|
|
|
|
2014-01-21 23:26:01 +00:00
|
|
|
// Calculate the appropriate source and destination rectangle to
|
|
|
|
// get a correctly scaled picture, including pan-scan.
|
|
|
|
// out_src: visible part of the video
|
|
|
|
// out_dst: area of screen covered by the video source rectangle
|
|
|
|
// out_osd: OSD size, OSD margins, etc.
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// Must be called from the VO thread only.
|
2014-01-21 23:26:01 +00:00
|
|
|
void vo_get_src_dst_rects(struct vo *vo, struct mp_rect *out_src,
|
|
|
|
struct mp_rect *out_dst, struct mp_osd_res *out_osd)
|
|
|
|
{
|
2014-06-01 15:24:19 +00:00
|
|
|
if (!vo->params) {
|
|
|
|
*out_src = *out_dst = (struct mp_rect){0};
|
|
|
|
*out_osd = (struct mp_osd_res){0};
|
2014-05-05 22:33:59 +00:00
|
|
|
return;
|
2014-06-01 15:24:19 +00:00
|
|
|
}
|
2014-04-20 19:36:56 +00:00
|
|
|
mp_get_src_dst_rects(vo->log, vo->opts, vo->driver->caps, vo->params,
|
|
|
|
vo->dwidth, vo->dheight, vo->monitor_par,
|
|
|
|
out_src, out_dst, out_osd);
|
2014-01-21 23:26:01 +00:00
|
|
|
}
|
|
|
|
|
2015-01-23 19:56:11 +00:00
|
|
|
// flip_page[_timed] will be called offset_us microseconds too early.
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
// (For vo_vdpau, which does its own timing.)
|
2015-07-20 19:12:46 +00:00
|
|
|
// num_req_frames set the requested number of requested vo_frame.frames.
|
|
|
|
// (For vo_opengl interpolation.)
|
2015-11-25 21:10:55 +00:00
|
|
|
void vo_set_queue_params(struct vo *vo, int64_t offset_us, int num_req_frames)
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-01-23 19:56:11 +00:00
|
|
|
in->flip_queue_offset = offset_us;
|
2015-07-20 19:12:46 +00:00
|
|
|
in->req_frames = MPCLAMP(num_req_frames, 1, VO_MAX_REQ_FRAMES);
|
2015-07-01 17:22:40 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
}
|
|
|
|
|
2015-07-20 19:12:46 +00:00
|
|
|
int vo_get_num_req_frames(struct vo *vo)
|
2015-07-01 17:22:40 +00:00
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-07-20 19:12:46 +00:00
|
|
|
int res = in->req_frames;
|
video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.
In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.
This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.
Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.
Side note:
Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.
As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 21:02:08 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
2015-07-01 17:22:40 +00:00
|
|
|
return res;
|
2011-12-06 19:23:54 +00:00
|
|
|
}
|
|
|
|
|
2014-08-17 00:50:59 +00:00
|
|
|
int64_t vo_get_vsync_interval(struct vo *vo)
|
|
|
|
{
|
2015-03-12 22:35:38 +00:00
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-07-01 17:25:13 +00:00
|
|
|
int64_t res = vo->in->vsync_interval > 1 ? vo->in->vsync_interval : -1;
|
2015-03-12 22:35:38 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return res;
|
2014-08-17 00:50:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 21:07:56 +00:00
|
|
|
// Returns duration of a display refresh in seconds.
|
|
|
|
double vo_get_estimated_vsync_interval(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-11-27 13:36:13 +00:00
|
|
|
double res = in->estimated_vsync_interval / 1e6;
|
2015-11-25 21:07:56 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
double vo_get_estimated_vsync_jitter(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
double res = in->estimated_vsync_jitter;
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-11-14 20:44:59 +00:00
|
|
|
// Get the time in seconds at after which the currently rendering frame will
|
|
|
|
// end. Returns positive values if the frame is yet to be finished, negative
|
|
|
|
// values if it already finished.
|
2015-08-10 16:43:25 +00:00
|
|
|
// This can only be called while no new frame is queued (after
|
|
|
|
// vo_is_ready_for_frame). Returns 0 for non-display synced frames, or if the
|
|
|
|
// deadline for continuous display was missed.
|
2015-11-14 20:44:59 +00:00
|
|
|
double vo_get_delay(struct vo *vo)
|
2015-08-10 16:43:25 +00:00
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
assert (!in->frame_queued);
|
|
|
|
int64_t res = 0;
|
2015-11-25 21:11:58 +00:00
|
|
|
if (in->base_vsync && in->vsync_interval > 1 && in->current_frame) {
|
|
|
|
res = in->base_vsync;
|
2015-08-10 16:43:25 +00:00
|
|
|
int extra = !!in->rendering;
|
|
|
|
res += (in->current_frame->num_vsyncs + extra) * in->vsync_interval;
|
|
|
|
if (!in->current_frame->display_synced)
|
|
|
|
res = 0;
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
2015-11-14 20:44:59 +00:00
|
|
|
return res ? (res - mp_time_us()) / 1e6 : 0;
|
2015-08-10 16:43:25 +00:00
|
|
|
}
|
|
|
|
|
2015-11-13 21:41:41 +00:00
|
|
|
int64_t vo_get_delayed_count(struct vo *vo)
|
2015-08-10 16:43:25 +00:00
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-11-13 21:41:41 +00:00
|
|
|
int64_t res = vo->in->delayed_count;
|
2015-08-10 16:43:25 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-03-13 12:14:11 +00:00
|
|
|
double vo_get_display_fps(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
double res = vo->in->display_fps;
|
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-11-02 19:26:51 +00:00
|
|
|
// Set specific event flags, and wakeup the playback core if needed.
|
2014-11-09 09:00:21 +00:00
|
|
|
// vo_query_and_reset_events() can retrieve the events again.
|
2014-11-02 19:26:51 +00:00
|
|
|
void vo_event(struct vo *vo, int event)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
if ((in->queued_events & event & VO_EVENTS_USER) != (event & VO_EVENTS_USER))
|
|
|
|
mp_input_wakeup(vo->input_ctx);
|
2015-05-13 07:28:59 +00:00
|
|
|
if (event)
|
|
|
|
wakeup_locked(vo);
|
2014-11-02 19:26:51 +00:00
|
|
|
in->queued_events |= event;
|
2015-03-12 22:35:38 +00:00
|
|
|
in->internal_events |= event;
|
2014-11-02 19:26:51 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check event flags set with vo_event(). Return the mask of events that was
|
2014-11-09 09:00:21 +00:00
|
|
|
// set and included in the events parameter. Clear the returned events.
|
|
|
|
int vo_query_and_reset_events(struct vo *vo, int events)
|
2014-11-02 19:26:51 +00:00
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
|
|
|
int r = in->queued_events & events;
|
2014-11-09 09:00:21 +00:00
|
|
|
in->queued_events &= ~(unsigned)r;
|
2014-11-02 19:26:51 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-01-24 21:56:02 +00:00
|
|
|
struct mp_image *vo_get_current_frame(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct vo_internal *in = vo->in;
|
|
|
|
pthread_mutex_lock(&in->lock);
|
2015-07-01 17:24:28 +00:00
|
|
|
struct mp_image *r = NULL;
|
|
|
|
if (vo->in->current_frame)
|
|
|
|
r = mp_image_new_ref(vo->in->current_frame->current);
|
2015-01-24 21:56:02 +00:00
|
|
|
pthread_mutex_unlock(&in->lock);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-07-01 17:24:28 +00:00
|
|
|
static void destroy_frame(void *p)
|
|
|
|
{
|
|
|
|
struct vo_frame *frame = p;
|
|
|
|
for (int n = 0; n < frame->num_frames; n++)
|
|
|
|
talloc_free(frame->frames[n]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return a new reference to the given frame. The image pointers are also new
|
|
|
|
// references. Calling talloc_free() on the frame unrefs all currently set
|
|
|
|
// image references. (Assuming current==frames[0].)
|
|
|
|
struct vo_frame *vo_frame_ref(struct vo_frame *frame)
|
|
|
|
{
|
|
|
|
if (!frame)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
struct vo_frame *new = talloc_ptrtype(NULL, new);
|
|
|
|
talloc_set_destructor(new, destroy_frame);
|
|
|
|
*new = *frame;
|
|
|
|
for (int n = 0; n < frame->num_frames; n++) {
|
|
|
|
new->frames[n] = mp_image_new_ref(frame->frames[n]);
|
|
|
|
if (!new->frames[n])
|
|
|
|
abort(); // OOM on tiny allocs
|
|
|
|
}
|
|
|
|
new->current = new->num_frames ? new->frames[0] : NULL;
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2015-04-16 20:29:25 +00:00
|
|
|
/*
|
|
|
|
* lookup an integer in a table, table must have 0 as the last key
|
|
|
|
* param: key key to search for
|
|
|
|
* returns translation corresponding to key or "to" value of last mapping
|
2014-04-22 19:03:52 +00:00
|
|
|
* if not found.
|
|
|
|
*/
|
|
|
|
int lookup_keymap_table(const struct mp_keymap *map, int key)
|
|
|
|
{
|
|
|
|
while (map->from && map->from != key)
|
|
|
|
map++;
|
|
|
|
return map->to;
|
|
|
|
}
|