summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/options.rst2
-rw-r--r--DOCS/man/en/vo.rst5
-rw-r--r--Makefile1
-rwxr-xr-xTOOLS/mpv_identify.sh2
-rwxr-xr-xconfigure12
-rw-r--r--demux/demux.c13
-rw-r--r--demux/demux.h2
-rw-r--r--demux/demux_lavf.c23
-rw-r--r--demux/demux_libass.c2
-rw-r--r--demux/demux_mf.c5
-rw-r--r--demux/demux_mkv.c14
-rw-r--r--demux/demux_raw.c8
-rw-r--r--demux/demux_subreader.c2
-rw-r--r--mpvcore/player/loadfile.c5
-rw-r--r--mpvcore/player/playloop.c32
-rw-r--r--stream/stream.c16
-rw-r--r--video/decode/dec_video.h5
-rw-r--r--video/decode/lavc.h2
-rw-r--r--video/decode/vaapi.c1
-rw-r--r--video/decode/vd_lavc.c7
-rw-r--r--video/mp_image.c22
-rw-r--r--video/mp_image.h3
-rw-r--r--video/out/gl_common.c9
-rw-r--r--video/out/gl_common.h39
-rw-r--r--video/out/gl_hwdec_vaglx.c140
-rw-r--r--video/out/gl_video.c123
-rw-r--r--video/out/gl_video.h4
-rw-r--r--video/out/vo_opengl.c73
28 files changed, 478 insertions, 94 deletions
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst
index 18542b2e37..f28280f73f 100644
--- a/DOCS/man/en/options.rst
+++ b/DOCS/man/en/options.rst
@@ -1118,7 +1118,7 @@ OPTIONS
:no: always use software decoding (default)
:auto: see below
:vdpau: requires ``--vo=vdpau`` (Linux only)
- :vaapi: requires ``--vo=vaapi`` (Linux with Intel GPUs only)
+ :vaapi: requires ``--vo=opengl`` or ``--vo=vaapi`` (Linux with Intel GPUs only)
:vaapi-copy: copies video back into system RAM (Linux with Intel GPUs only)
:vda: requires ``--vo=corevideo`` (OSX only)
:crystalhd: Broadcom Crystal HD
diff --git a/DOCS/man/en/vo.rst b/DOCS/man/en/vo.rst
index 4590ec33f2..fd14c6a128 100644
--- a/DOCS/man/en/vo.rst
+++ b/DOCS/man/en/vo.rst
@@ -241,6 +241,11 @@ Available video output drivers are:
Some features are available with OpenGL 3 capable graphics drivers only
(or if the necessary extensions are available).
+ Hardware decoding over OpenGL-interop is supported to some degree. Note
+ that in this mode, some corner case might not be gracefully handled, and
+ colorspace conversion and chroma upsampling is generally in the hand of
+ the hardware decoder APIs.
+
``lscale=<filter>``
``bilinear``
diff --git a/Makefile b/Makefile
index bed21f20e5..e1cacc0ea5 100644
--- a/Makefile
+++ b/Makefile
@@ -121,6 +121,7 @@ SOURCES-$(VAAPI) += video/out/vo_vaapi.c \
video/decode/vaapi.c \
video/vaapi.c
SOURCES-$(VAAPI_VPP) += video/filter/vf_vavpp.c
+SOURCES-$(VAAPI_GLX) += video/out/gl_hwdec_vaglx.c
SOURCES-$(X11) += video/out/vo_x11.c video/out/x11_common.c
SOURCES-$(XV) += video/out/vo_xv.c
diff --git a/TOOLS/mpv_identify.sh b/TOOLS/mpv_identify.sh
index 0c4dfc5b02..b1c17f75c2 100755
--- a/TOOLS/mpv_identify.sh
+++ b/TOOLS/mpv_identify.sh
@@ -104,7 +104,7 @@ for __midentify__key in $__midentify__allprops; do
eval unset $__midentify__nextprefix$__midentify__key
done
-__midentify__output=`$MPV --playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet "$@"`
+__midentify__output=`$MPV --playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet --no-cache --no-config "$@"`
__midentify__fileindex=0
__midentify__prefix=
while :; do
diff --git a/configure b/configure
index 2b31424daa..8de1ba52e8 100755
--- a/configure
+++ b/configure
@@ -1863,6 +1863,8 @@ echores "$_vdpau"
echocheck "VAAPI"
_vaapi_vpp=no
def_vaapi_vpp='#define HAVE_VAAPI_VPP 0'
+_vaapi_glx=no
+def_vaapi_glx='#define HAVE_VAAPI_GLX 0'
if test "$_vaapi" = auto && test "$_x11" = yes ; then
_vaapi=no
if test "$_dl" = yes ; then
@@ -1886,7 +1888,13 @@ if test "$_vaapi" = yes ; then
_vaapi_vpp=yes
def_vaapi_vpp='#define HAVE_VAAPI_VPP 1'
fi
- echores "$_vaapi_vpp"
+ echores "$_vaapi_glx"
+ echocheck "VAAPI GLX"
+ if pkg_config_add 'libva-glx >= 0.32.0' ; then
+ _vaapi_glx=yes
+ def_vaapi_glx='#define HAVE_VAAPI_GLX 1'
+ fi
+ echores "$_vaapi_glx"
fi
@@ -3321,6 +3329,7 @@ VDA = $_vda
VDA_REFCOUNTING = $_vda_refcounting
VAAPI = $_vaapi
VAAPI_VPP = $_vaapi_vpp
+VAAPI_GLX = $_vaapi_glx
WIN32 = $_win32
X11 = $_x11
WAYLAND = $_wayland
@@ -3501,6 +3510,7 @@ $def_vda
$def_vda_refcounting
$def_vaapi
$def_vaapi_vpp
+$def_vaapi_glx
$def_vaapi_hwaccel
$def_vm
$def_x11
diff --git a/demux/demux.c b/demux/demux.c
index eeb979be9d..a0164d529a 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -533,9 +533,8 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
.type = desc->type,
.stream = stream,
.stream_pts = MP_NOPTS_VALUE,
- .movi_start = stream->start_pos,
- .movi_end = stream->end_pos,
- .seekable = 1,
+ .seekable = (stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK &&
+ stream->end_pos > 0,
.accurate_seek = true,
.filepos = -1,
.opts = opts,
@@ -566,6 +565,12 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
add_stream_chapters(demuxer);
demuxer_sort_chapters(demuxer);
demux_info_update(demuxer);
+ // Pretend we can seek if we can't seek, but there's a cache.
+ if (!demuxer->seekable && stream->uncached_stream) {
+ mp_msg(MSGT_DEMUXER, MSGL_WARN,
+ "File is not seekable, but there's a cache: enabling seeking.\n");
+ demuxer->seekable = true;
+ }
return demuxer;
}
@@ -634,7 +639,7 @@ void demux_flush(demuxer_t *demuxer)
int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
{
if (!demuxer->seekable) {
- mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in this file.\n");
+ mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "Cannot seek in this file.\n");
return 0;
}
diff --git a/demux/demux.h b/demux/demux.h
index 0c8f9cb3f8..1c8562eb63 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -166,8 +166,6 @@ typedef struct demuxer {
const demuxer_desc_t *desc; ///< Demuxer description structure
const char *filetype; // format name when not identified by demuxer (libavformat)
int64_t filepos; // input stream current pos.
- int64_t movi_start;
- int64_t movi_end;
struct stream *stream;
double stream_pts; // current stream pts, if applicable (e.g. dvd)
char *filename; // same as stream->url
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index e80db5aed4..b2dfcb2193 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -584,9 +584,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
}
}
- if (!(priv->avif->flags & AVFMT_NOFILE) &&
- demuxer->stream->type != STREAMTYPE_AVDEVICE)
+ if ((priv->avif->flags & AVFMT_NOFILE) ||
+ demuxer->stream->type == STREAMTYPE_AVDEVICE)
{
+ // This might be incorrect.
+ demuxer->seekable = true;
+ } else {
void *buffer = av_malloc(lavfdopts->buffersize);
if (!buffer)
return -1;
@@ -597,9 +600,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
return -1;
}
priv->pb->read_seek = mp_read_seek;
- priv->pb->seekable = demuxer->stream->end_pos
- && (demuxer->stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK
- ? AVIO_SEEKABLE_NORMAL : 0;
+ priv->pb->seekable = demuxer->seekable ? AVIO_SEEKABLE_NORMAL : 0;
avfc->pb = priv->pb;
}
@@ -857,12 +858,12 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, int flags)
avsflags = AVSEEK_FLAG_BACKWARD;
if (flags & SEEK_FACTOR) {
- if (demuxer->movi_end > 0 && demuxer->ts_resets_possible &&
+ struct stream *s = demuxer->stream;
+ if (s->end_pos > 0 && demuxer->ts_resets_possible &&
!(priv->avif->flags & AVFMT_NO_BYTE_SEEK))
{
avsflags |= AVSEEK_FLAG_BYTE;
- priv->last_pts = (demuxer->movi_end - demuxer->movi_start) *
- rel_seek_secs;
+ priv->last_pts = (s->end_pos - s->start_pos) * rel_seek_secs;
} else if (priv->avfc->duration != 0 &&
priv->avfc->duration != AV_NOPTS_VALUE)
{
@@ -923,12 +924,12 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg)
switch (cmd) {
case DEMUXER_CTRL_GET_TIME_LENGTH:
if (priv->seek_by_bytes) {
+ struct stream *s = demuxer->stream;
/* Our bitrate estimate may be better than would be used in
* otherwise similar fallback code at higher level */
- if (demuxer->movi_end <= 0)
+ if (s->end_pos <= 0)
return DEMUXER_CTRL_DONTKNOW;
- *(double *)arg = (demuxer->movi_end - demuxer->movi_start) * 8 /
- priv->bitrate;
+ *(double *)arg = (s->end_pos - s->start_pos) * 8 / priv->bitrate;
return DEMUXER_CTRL_GUESS;
}
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
diff --git a/demux/demux_libass.c b/demux/demux_libass.c
index d98cdbb5a4..73c8b3a5c8 100644
--- a/demux/demux_libass.c
+++ b/demux/demux_libass.c
@@ -100,6 +100,8 @@ static int d_check_file(struct demuxer *demuxer, enum demux_check check)
sh->sub->track = track;
sh->codec = "ass";
+ demuxer->seekable = true;
+
return 0;
}
diff --git a/demux/demux_mf.c b/demux/demux_mf.c
index 0d7b2ece8a..50888f59ad 100644
--- a/demux/demux_mf.c
+++ b/demux/demux_mf.c
@@ -85,7 +85,6 @@ static int demux_mf_fill_buffer(demuxer_t *demuxer)
demux_packet_t *dp = new_demux_packet(data.len);
memcpy(dp->buffer, data.start, data.len);
dp->pts = mf->curr_frame / mf->sh->fps;
- dp->pos = mf->curr_frame;
dp->keyframe = true;
demuxer_add_packet(demuxer, demuxer->streams[0], dp);
}
@@ -200,9 +199,6 @@ static int demux_open_mf(demuxer_t* demuxer, enum demux_check check)
mf->curr_frame = 0;
- demuxer->movi_start = 0;
- demuxer->movi_end = mf->nr_of_files - 1;
-
// create a new video stream header
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO);
sh_video = sh->video;
@@ -214,6 +210,7 @@ static int demux_open_mf(demuxer_t* demuxer, enum demux_check check)
mf->sh = sh_video;
demuxer->priv=(void*)mf;
+ demuxer->seekable = true;
return 0;
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index eb352e0f64..6110d25930 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -1029,7 +1029,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
continue;
}
uint64_t pos = seek->seek_position + mkv_d->segment_start;
- if (pos >= demuxer->movi_end) {
+ if (pos >= s->end_pos) {
mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] SeekHead position beyond "
"end of file - incomplete file?\n");
continue;
@@ -1844,14 +1844,6 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
display_create_tracks(demuxer);
- if (s->end_pos == 0) {
- demuxer->seekable = 0;
- } else {
- demuxer->movi_start = s->start_pos;
- demuxer->movi_end = s->end_pos;
- demuxer->seekable = 1;
- }
-
return 0;
}
@@ -2713,7 +2705,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
}
demux_mkv_fill_buffer(demuxer);
- } else if ((demuxer->movi_end <= 0) || !(flags & SEEK_ABSOLUTE))
+ } else if (!(flags & SEEK_ABSOLUTE))
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n");
else {
stream_t *s = demuxer->stream;
@@ -2729,7 +2721,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
return;
}
- target_filepos = (uint64_t) (demuxer->movi_end * rel_seek_secs);
+ target_filepos = (uint64_t) (s->end_pos * rel_seek_secs);
for (i = 0; i < mkv_d->num_indexes; i++)
if (mkv_d->indexes[i].tnum == v_tnum)
if ((index == NULL)
diff --git a/demux/demux_raw.c b/demux/demux_raw.c
index 4d6e171ad4..01cf3574a0 100644
--- a/demux/demux_raw.c
+++ b/demux/demux_raw.c
@@ -100,9 +100,6 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
w->wBitsPerSample = 8 * samplesize;
w->cbSize = 0;
- demuxer->movi_start = demuxer->stream->start_pos;
- demuxer->movi_end = demuxer->stream->end_pos;
-
struct priv *p = talloc_ptrtype(demuxer, p);
demuxer->priv = p;
*p = (struct priv) {
@@ -185,9 +182,6 @@ static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check)
sh_video->disp_h = height;
sh_video->i_bps = fps * imgsize;
- demuxer->movi_start = demuxer->stream->start_pos;
- demuxer->movi_end = demuxer->stream->end_pos;
-
struct priv *p = talloc_ptrtype(demuxer, p);
demuxer->priv = p;
*p = (struct priv) {
@@ -207,7 +201,7 @@ static int raw_fill_buffer(demuxer_t *demuxer)
return 0;
struct demux_packet *dp = new_demux_packet(p->frame_size * p->read_frames);
- dp->pos = stream_tell(demuxer->stream) - demuxer->movi_start;
+ dp->pos = stream_tell(demuxer->stream) - demuxer->stream->start_pos;
dp->pts = (dp->pos / p->frame_size) / p->frame_rate;
int len = stream_read(demuxer->stream, dp->buffer, dp->len);
diff --git a/demux/demux_subreader.c b/demux/demux_subreader.c
index cc02e61595..21bcf21614 100644
--- a/demux/demux_subreader.c
+++ b/demux/demux_subreader.c
@@ -1358,6 +1358,8 @@ static int d_open_file(struct demuxer *demuxer, enum demux_check check)
add_sub_data(demuxer, sd);
subdata_free(sd);
+ demuxer->seekable = true;
+
return 0;
}
diff --git a/mpvcore/player/loadfile.c b/mpvcore/player/loadfile.c
index 24b81934ad..baa49f0db5 100644
--- a/mpvcore/player/loadfile.c
+++ b/mpvcore/player/loadfile.c
@@ -894,8 +894,9 @@ static void print_resolve_contents(struct mp_log *log,
// from the given playlist pl, so the entries don't actually need to be copied.
static void transfer_playlist(struct MPContext *mpctx, struct playlist *pl)
{
- if (mpctx->demuxer->playlist->first) {
- playlist_transfer_entries(mpctx->playlist, mpctx->demuxer->playlist);
+ if (pl->first) {
+ playlist_transfer_entries(mpctx->playlist, pl);
+ // current entry is replaced
if (mpctx->playlist->current)
playlist_remove(mpctx->playlist, mpctx->playlist->current);
} else {
diff --git a/mpvcore/player/playloop.c b/mpvcore/player/playloop.c
index 1162572946..d4db03c446 100644
--- a/mpvcore/player/playloop.c
+++ b/mpvcore/player/playloop.c
@@ -206,8 +206,8 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
}
// return -1 if seek failed (non-seekable stream?), 0 otherwise
-static int seek(MPContext *mpctx, struct seek_params seek,
- bool timeline_fallthrough)
+static int mp_seek(MPContext *mpctx, struct seek_params seek,
+ bool timeline_fallthrough)
{
struct MPOpts *opts = mpctx->opts;
uint64_t prev_seek_ts = mpctx->vo_pts_history_seek_ts;
@@ -215,6 +215,11 @@ static int seek(MPContext *mpctx, struct seek_params seek,
if (!mpctx->demuxer)
return -1;
+ if (!mpctx->demuxer->seekable) {
+ MP_ERR(mpctx, "Can't seek in this file.\n");
+ return -1;
+ }
+
if (mpctx->stop_play == AT_END_OF_FILE)
mpctx->stop_play = KEEP_PLAYING;
bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts;
@@ -387,7 +392,7 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
void execute_queued_seek(struct MPContext *mpctx)
{
if (mpctx->seek.type) {
- seek(mpctx, mpctx->seek, false);
+ mp_seek(mpctx, mpctx->seek, false);
mpctx->seek = (struct seek_params){0};
}
}
@@ -452,11 +457,12 @@ double get_current_pos_ratio(struct MPContext *mpctx, bool use_range)
if (len > 0 && !demuxer->ts_resets_possible) {
ans = MPCLAMP((pos - start) / len, 0, 1);
} else {
- int64_t size = (demuxer->movi_end - demuxer->movi_start);
+ struct stream *s = demuxer->stream;
+ int64_t size = s->end_pos - s->start_pos;
int64_t fpos = demuxer->filepos > 0 ?
demuxer->filepos : stream_tell(demuxer->stream);
if (size > 0)
- ans = MPCLAMP((double)(fpos - demuxer->movi_start) / size, 0, 1);
+ ans = MPCLAMP((double)(fpos - s->start_pos) / size, 0, 1);
}
if (use_range) {
if (mpctx->opts->play_frames > 0)
@@ -812,10 +818,10 @@ static void handle_backstep(struct MPContext *mpctx)
// The whole point is getting frames _before_ that PTS,
// so apply an arbitrary offset. (In theory the offset
// has to be large enough to reach the previous frame.)
- seek(mpctx, (struct seek_params){
- .type = MPSEEK_ABSOLUTE,
- .amount = current_pts - 1.0,
- }, false);
+ mp_seek(mpctx, (struct seek_params){
+ .type = MPSEEK_ABSOLUTE,
+ .amount = current_pts - 1.0,
+ }, false);
// Don't leave hr-seek mode. If all goes right, hr-seek
// mode is cancelled as soon as the frame before
// current_pts is found during hr-seeking.
@@ -1184,10 +1190,10 @@ void run_playloop(struct MPContext *mpctx)
&& (opts->gapless_audio || buffered_audio < 0.05)
&& (!mpctx->paused || was_restart)) {
if (end_is_chapter) {
- seek(mpctx, (struct seek_params){
- .type = MPSEEK_ABSOLUTE,
- .amount = mpctx->timeline[mpctx->timeline_part+1].start
- }, true);
+ mp_seek(mpctx, (struct seek_params){
+ .type = MPSEEK_ABSOLUTE,
+ .amount = mpctx->timeline[mpctx->timeline_part+1].start
+ }, true);
} else
mpctx->stop_play = AT_END_OF_FILE;
sleeptime = 0;
diff --git a/stream/stream.c b/stream/stream.c
index fbc324563a..3844721346 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -318,8 +318,8 @@ static int open_internal(const stream_info_t *sinfo, struct stream *underlying,
if (s->seek && !(s->flags & MP_STREAM_SEEK))
s->flags |= MP_STREAM_SEEK;
- if (s->flags & MP_STREAM_FAST_SKIPPING)
- s->flags |= MP_STREAM_SEEK_FW;
+ if (!(s->flags & MP_STREAM_SEEK))
+ s->end_pos = 0;
s->uncached_type = s->type;
@@ -387,6 +387,8 @@ static int stream_reconnect(stream_t *s)
#define RECONNECT_SLEEP_MS 1000
if (!s->streaming)
return 0;
+ if (!(s->flags & MP_STREAM_SEEK_FW))
+ return 0;
int64_t pos = s->pos;
for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) {
mp_msg(MSGT_STREAM, MSGL_WARN,
@@ -601,7 +603,7 @@ static int stream_skip_read(struct stream *s, int64_t len)
static int stream_seek_unbuffered(stream_t *s, int64_t newpos)
{
if (newpos != s->pos) {
- if (!s->seek || !(s->flags & MP_STREAM_SEEK)) {
+ if (newpos > s->pos && !(s->flags & MP_STREAM_SEEK_FW)) {
mp_tmsg(MSGT_STREAM, MSGL_ERR, "Can not seek in this stream\n");
return 0;
}
@@ -628,7 +630,7 @@ static int stream_seek_long(stream_t *s, int64_t pos)
s->eof = 0;
if (s->mode == STREAM_WRITE) {
- if (!s->seek || !s->seek(s, pos))
+ if (!(s->flags & MP_STREAM_SEEK) || !s->seek(s, pos))
return 0;
return 1;
}
@@ -640,7 +642,9 @@ static int stream_seek_long(stream_t *s, int64_t pos)
mp_msg(MSGT_STREAM, MSGL_DBG3, "Seek from %" PRId64 " to %" PRId64
" (with offset %d)\n", s->pos, pos, (int)(pos - newpos));
- if (!s->seek && (s->flags & MP_STREAM_FAST_SKIPPING) && pos >= s->pos) {
+ if (pos >= s->pos && !(s->flags & MP_STREAM_SEEK) &&
+ (s->flags & MP_STREAM_FAST_SKIPPING))
+ {
// skipping is handled by generic code below
} else if (stream_seek_unbuffered(s, newpos) >= 0) {
return 0;
@@ -709,6 +713,8 @@ int stream_control(stream_t *s, int cmd, void *arg)
void stream_update_size(stream_t *s)
{
+ if (!(s->flags & MP_STREAM_SEEK))
+ return;
uint64_t size;
if (stream_control(s, STREAM_CTRL_GET_SIZE, &size) == STREAM_OK) {
if (size > s->end_pos)
diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h
index 549d208f81..03b72907ef 100644
--- a/video/decode/dec_video.h
+++ b/video/decode/dec_video.h
@@ -47,6 +47,11 @@ int vd_control(struct sh_video *sh_video, int cmd, void *arg);
struct mp_hwdec_info {
struct mp_vdpau_ctx *vdpau_ctx;
struct mp_vaapi_ctx *vaapi_ctx;
+ // Can be used to lazily load a requested API.
+ // api_name is e.g. "vdpau" (like the fields above, without "_ctx")
+ // Can be NULL, is idempotent, caller checks _ctx fields for success/access.
+ void (*load_api)(struct mp_hwdec_info *info, const char *api_name);
+ void *load_api_ctx;
};
#endif /* MPLAYER_DEC_VIDEO_H */
diff --git a/video/decode/lavc.h b/video/decode/lavc.h
index 9e2533cbd5..af206bc82a 100644
--- a/video/decode/lavc.h
+++ b/video/decode/lavc.h
@@ -86,6 +86,8 @@ bool hwdec_check_codec_support(const char *decoder,
const struct hwdec_profile_entry *table);
int hwdec_get_max_refs(struct lavc_ctx *ctx);
+void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name);
+
// lavc_dr1.c
int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame);
void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame);
diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c
index bb2a6c1049..4603a3c5e1 100644
--- a/video/decode/vaapi.c
+++ b/video/decode/vaapi.c
@@ -421,6 +421,7 @@ static int init(struct lavc_ctx *ctx)
static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
const char *decoder)
{
+ hwdec_request_api(info, "vaapi");
if (!info || !info->vaapi_ctx)
return HWDEC_ERR_NO_CTX;
if (!hwdec_check_codec_support(decoder, profiles))
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 64542be69d..c6a939ec51 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -46,6 +46,7 @@
#include "video/img_format.h"
#include "video/mp_image_pool.h"
#include "video/filter/vf.h"
+#include "video/decode/dec_video.h"
#include "demux/stheader.h"
#include "demux/demux_packet.h"
#include "osdep/numcores.h"
@@ -195,6 +196,12 @@ int hwdec_get_max_refs(struct lavc_ctx *ctx)
return ctx->avctx->codec_id == AV_CODEC_ID_H264 ? 16 : 2;
}
+void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name)
+{
+ if (info && info->load_api)
+ info->load_api(info, api_name);
+}
+
static int hwdec_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
const char *decoder, const char **hw_decoder)
{
diff --git a/video/mp_image.c b/video/mp_image.c
index 3bc76b669e..9b96bab67d 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -36,6 +36,8 @@
#include "memcpy_pic.h"
#include "fmt-conversion.h"
+#include "video/filter/vf.h"
+
#if HAVE_PTHREADS
#include <pthread.h>
static pthread_mutex_t refcount_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -468,6 +470,26 @@ void mp_image_set_params(struct mp_image *image,
image->chroma_location = params->chroma_location;
}
+// Set most image parameters, but not image format or size.
+// Display size is used to set the PAR.
+void mp_image_set_attributes(struct mp_image *image,
+ const struct mp_image_params *params)
+{
+ struct mp_image_params nparams = *params;
+ nparams.imgfmt = image->imgfmt;
+ nparams.w = image->w;
+ nparams.h = image->h;
+ if (nparams.imgfmt != params->imgfmt)
+ mp_image_params_guess_csp(&nparams);
+ if (nparams.w != params->w || nparams.h != params->h) {
+ if (nparams.d_w && nparams.d_h) {
+ vf_rescale_dsize(&nparams.d_w, &nparams.d_h,
+ params->w, params->h, nparams.w, nparams.h);
+ }
+ }
+ mp_image_set_params(image, &nparams);
+}
+
void mp_image_set_colorspace_details(struct mp_image *image,
struct mp_csp_details *csp)
{
diff --git a/video/mp_image.h b/video/mp_image.h
index e198c4e547..f7e7353475 100644
--- a/video/mp_image.h
+++ b/video/mp_image.h
@@ -153,6 +153,9 @@ void mp_image_params_from_image(struct mp_image_params *params,
void mp_image_set_params(struct mp_image *image,
const struct mp_image_params *params);
+void mp_image_set_attributes(struct mp_image *image,
+ const struct mp_image_params *params);
+
struct AVFrame;
void mp_image_copy_fields_from_av_frame(struct mp_image *dst,
struct AVFrame *src);
diff --git a/video/out/gl_common.c b/video/out/gl_common.c
index d39a09df16..f3e38a2171 100644
--- a/video/out/gl_common.c
+++ b/video/out/gl_common.c
@@ -1008,3 +1008,12 @@ void mp_log_source(struct mp_log *log, int lev, const char *src)
src = next;
}
}
+
+extern const struct gl_hwdec_driver gl_hwdec_vaglx;
+
+const struct gl_hwdec_driver *mpgl_hwdec_drivers[] = {
+#if HAVE_VAAPI_GLX
+ &gl_hwdec_vaglx,
+#endif
+ NULL
+};
diff --git a/video/out/gl_common.h b/video/out/gl_common.h
index 41d30bb001..4722f3d52e 100644
--- a/video/out/gl_common.h
+++ b/video/out/gl_common.h
@@ -164,6 +164,45 @@ void mpgl_set_backend_w32(MPGLContext *ctx);
void mpgl_set_backend_x11(MPGLContext *ctx);
void mpgl_set_backend_wayland(MPGLContext *ctx);
+struct mp_hwdec_info;
+
+struct gl_hwdec {
+ const struct gl_hwdec_driver *driver;
+ struct mp_log *log;
+ struct MPGLContext *mpgl;
+ struct mp_hwdec_info *info;
+ // For free use by hwdec driver
+ void *priv;
+ // hwdec backends must set this to an IMGFMT_ that has an equivalent
+ // internal representation in gl_video.c as the hardware texture.
+ // It's used to build the rendering chain, and also as screenshot format.
+ int converted_imgfmt;
+};
+
+struct gl_hwdec_driver {
+ // Same name as used by mp_hwdec_info->load_api()
+ const char *api_name;
+ // Test whether the given IMGFMT_ is supported.
+ bool (*query_format)(int imgfmt);
+ // Create the hwdec device. It must fill in hw->info, if applicable.
+ // This also must set hw->converted_imgfmt.
+ int (*create)(struct gl_hwdec *hw);
+ // Prepare for rendering video. (E.g. create textures.)
+ // Called on initialization, and every time the video size changes.
+ int (*reinit)(struct gl_hwdec *hw, int w, int h);
+ // Return textures that contain the given hw_image.
+ // Note that the caller keeps a reference to hw_image until unbind_image
+ // is called, so the callee doesn't need to do that.
+ int (*load_image)(struct gl_hwdec *hw, struct mp_image *hw_image,
+ GLuint *out_textures);
+ // Undo load_image(). The user of load_image() calls this when the textures
+ // are not needed anymore.
+ void (*unload_image)(struct gl_hwdec *hw);
+ void (*destroy)(struct gl_hwdec *hw);
+};
+
+extern const struct gl_hwdec_driver *mpgl_hwdec_drivers[];
+
void *mp_getdladdr(const char *s);
void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
diff --git a/video/out/gl_hwdec_vaglx.c b/video/out/gl_hwdec_vaglx.c
new file mode 100644
index 0000000000..9e1030fe49
--- /dev/null
+++ b/video/out/gl_hwdec_vaglx.c
@@ -0,0 +1,140 @@
+/*
+ * This file is part of mpv.
+ *
+ * Parts based on the MPlayer VA-API patch (see vo_vaapi.c).
+ *
+ * mpv is free software; you can redistribute it and/or modify
+ * 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.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the