mirror of https://github.com/mpv-player/mpv
Merge branch 'master' into have_configure
Conflicts: configure
This commit is contained in:
commit
f7b2d644ef
|
@ -1118,7 +1118,7 @@ OPTIONS
|
||||||
:no: always use software decoding (default)
|
:no: always use software decoding (default)
|
||||||
:auto: see below
|
:auto: see below
|
||||||
:vdpau: requires ``--vo=vdpau`` (Linux only)
|
: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)
|
:vaapi-copy: copies video back into system RAM (Linux with Intel GPUs only)
|
||||||
:vda: requires ``--vo=corevideo`` (OSX only)
|
:vda: requires ``--vo=corevideo`` (OSX only)
|
||||||
:crystalhd: Broadcom Crystal HD
|
:crystalhd: Broadcom Crystal HD
|
||||||
|
|
|
@ -241,6 +241,11 @@ Available video output drivers are:
|
||||||
Some features are available with OpenGL 3 capable graphics drivers only
|
Some features are available with OpenGL 3 capable graphics drivers only
|
||||||
(or if the necessary extensions are available).
|
(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>``
|
``lscale=<filter>``
|
||||||
|
|
||||||
``bilinear``
|
``bilinear``
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -121,6 +121,7 @@ SOURCES-$(VAAPI) += video/out/vo_vaapi.c \
|
||||||
video/decode/vaapi.c \
|
video/decode/vaapi.c \
|
||||||
video/vaapi.c
|
video/vaapi.c
|
||||||
SOURCES-$(VAAPI_VPP) += video/filter/vf_vavpp.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-$(X11) += video/out/vo_x11.c video/out/x11_common.c
|
||||||
SOURCES-$(XV) += video/out/vo_xv.c
|
SOURCES-$(XV) += video/out/vo_xv.c
|
||||||
|
|
|
@ -104,7 +104,7 @@ for __midentify__key in $__midentify__allprops; do
|
||||||
eval unset $__midentify__nextprefix$__midentify__key
|
eval unset $__midentify__nextprefix$__midentify__key
|
||||||
done
|
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__fileindex=0
|
||||||
__midentify__prefix=
|
__midentify__prefix=
|
||||||
while :; do
|
while :; do
|
||||||
|
|
|
@ -1863,6 +1863,8 @@ echores "$_vdpau"
|
||||||
echocheck "VAAPI"
|
echocheck "VAAPI"
|
||||||
_vaapi_vpp=no
|
_vaapi_vpp=no
|
||||||
def_vaapi_vpp='#define HAVE_VAAPI_VPP 0'
|
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
|
if test "$_vaapi" = auto && test "$_x11" = yes ; then
|
||||||
_vaapi=no
|
_vaapi=no
|
||||||
if test "$_dl" = yes ; then
|
if test "$_dl" = yes ; then
|
||||||
|
@ -1886,7 +1888,13 @@ if test "$_vaapi" = yes ; then
|
||||||
_vaapi_vpp=yes
|
_vaapi_vpp=yes
|
||||||
def_vaapi_vpp='#define HAVE_VAAPI_VPP 1'
|
def_vaapi_vpp='#define HAVE_VAAPI_VPP 1'
|
||||||
fi
|
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
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -3321,6 +3329,7 @@ VDA = $_vda
|
||||||
VDA_REFCOUNTING = $_vda_refcounting
|
VDA_REFCOUNTING = $_vda_refcounting
|
||||||
VAAPI = $_vaapi
|
VAAPI = $_vaapi
|
||||||
VAAPI_VPP = $_vaapi_vpp
|
VAAPI_VPP = $_vaapi_vpp
|
||||||
|
VAAPI_GLX = $_vaapi_glx
|
||||||
WIN32 = $_win32
|
WIN32 = $_win32
|
||||||
X11 = $_x11
|
X11 = $_x11
|
||||||
WAYLAND = $_wayland
|
WAYLAND = $_wayland
|
||||||
|
@ -3501,6 +3510,7 @@ $def_vda
|
||||||
$def_vda_refcounting
|
$def_vda_refcounting
|
||||||
$def_vaapi
|
$def_vaapi
|
||||||
$def_vaapi_vpp
|
$def_vaapi_vpp
|
||||||
|
$def_vaapi_glx
|
||||||
$def_vaapi_hwaccel
|
$def_vaapi_hwaccel
|
||||||
$def_vm
|
$def_vm
|
||||||
$def_x11
|
$def_x11
|
||||||
|
|
|
@ -533,9 +533,8 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
|
||||||
.type = desc->type,
|
.type = desc->type,
|
||||||
.stream = stream,
|
.stream = stream,
|
||||||
.stream_pts = MP_NOPTS_VALUE,
|
.stream_pts = MP_NOPTS_VALUE,
|
||||||
.movi_start = stream->start_pos,
|
.seekable = (stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK &&
|
||||||
.movi_end = stream->end_pos,
|
stream->end_pos > 0,
|
||||||
.seekable = 1,
|
|
||||||
.accurate_seek = true,
|
.accurate_seek = true,
|
||||||
.filepos = -1,
|
.filepos = -1,
|
||||||
.opts = opts,
|
.opts = opts,
|
||||||
|
@ -566,6 +565,12 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
|
||||||
add_stream_chapters(demuxer);
|
add_stream_chapters(demuxer);
|
||||||
demuxer_sort_chapters(demuxer);
|
demuxer_sort_chapters(demuxer);
|
||||||
demux_info_update(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;
|
return demuxer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,7 +639,7 @@ void demux_flush(demuxer_t *demuxer)
|
||||||
int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
||||||
{
|
{
|
||||||
if (!demuxer->seekable) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,8 +166,6 @@ typedef struct demuxer {
|
||||||
const demuxer_desc_t *desc; ///< Demuxer description structure
|
const demuxer_desc_t *desc; ///< Demuxer description structure
|
||||||
const char *filetype; // format name when not identified by demuxer (libavformat)
|
const char *filetype; // format name when not identified by demuxer (libavformat)
|
||||||
int64_t filepos; // input stream current pos.
|
int64_t filepos; // input stream current pos.
|
||||||
int64_t movi_start;
|
|
||||||
int64_t movi_end;
|
|
||||||
struct stream *stream;
|
struct stream *stream;
|
||||||
double stream_pts; // current stream pts, if applicable (e.g. dvd)
|
double stream_pts; // current stream pts, if applicable (e.g. dvd)
|
||||||
char *filename; // same as stream->url
|
char *filename; // same as stream->url
|
||||||
|
|
|
@ -584,9 +584,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(priv->avif->flags & AVFMT_NOFILE) &&
|
if ((priv->avif->flags & AVFMT_NOFILE) ||
|
||||||
demuxer->stream->type != STREAMTYPE_AVDEVICE)
|
demuxer->stream->type == STREAMTYPE_AVDEVICE)
|
||||||
{
|
{
|
||||||
|
// This might be incorrect.
|
||||||
|
demuxer->seekable = true;
|
||||||
|
} else {
|
||||||
void *buffer = av_malloc(lavfdopts->buffersize);
|
void *buffer = av_malloc(lavfdopts->buffersize);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -597,9 +600,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
priv->pb->read_seek = mp_read_seek;
|
priv->pb->read_seek = mp_read_seek;
|
||||||
priv->pb->seekable = demuxer->stream->end_pos
|
priv->pb->seekable = demuxer->seekable ? AVIO_SEEKABLE_NORMAL : 0;
|
||||||
&& (demuxer->stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK
|
|
||||||
? AVIO_SEEKABLE_NORMAL : 0;
|
|
||||||
avfc->pb = priv->pb;
|
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;
|
avsflags = AVSEEK_FLAG_BACKWARD;
|
||||||
|
|
||||||
if (flags & SEEK_FACTOR) {
|
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))
|
!(priv->avif->flags & AVFMT_NO_BYTE_SEEK))
|
||||||
{
|
{
|
||||||
avsflags |= AVSEEK_FLAG_BYTE;
|
avsflags |= AVSEEK_FLAG_BYTE;
|
||||||
priv->last_pts = (demuxer->movi_end - demuxer->movi_start) *
|
priv->last_pts = (s->end_pos - s->start_pos) * rel_seek_secs;
|
||||||
rel_seek_secs;
|
|
||||||
} else if (priv->avfc->duration != 0 &&
|
} else if (priv->avfc->duration != 0 &&
|
||||||
priv->avfc->duration != AV_NOPTS_VALUE)
|
priv->avfc->duration != AV_NOPTS_VALUE)
|
||||||
{
|
{
|
||||||
|
@ -923,12 +924,12 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg)
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||||
if (priv->seek_by_bytes) {
|
if (priv->seek_by_bytes) {
|
||||||
|
struct stream *s = demuxer->stream;
|
||||||
/* Our bitrate estimate may be better than would be used in
|
/* Our bitrate estimate may be better than would be used in
|
||||||
* otherwise similar fallback code at higher level */
|
* otherwise similar fallback code at higher level */
|
||||||
if (demuxer->movi_end <= 0)
|
if (s->end_pos <= 0)
|
||||||
return DEMUXER_CTRL_DONTKNOW;
|
return DEMUXER_CTRL_DONTKNOW;
|
||||||
*(double *)arg = (demuxer->movi_end - demuxer->movi_start) * 8 /
|
*(double *)arg = (s->end_pos - s->start_pos) * 8 / priv->bitrate;
|
||||||
priv->bitrate;
|
|
||||||
return DEMUXER_CTRL_GUESS;
|
return DEMUXER_CTRL_GUESS;
|
||||||
}
|
}
|
||||||
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
||||||
|
|
|
@ -100,6 +100,8 @@ static int d_check_file(struct demuxer *demuxer, enum demux_check check)
|
||||||
sh->sub->track = track;
|
sh->sub->track = track;
|
||||||
sh->codec = "ass";
|
sh->codec = "ass";
|
||||||
|
|
||||||
|
demuxer->seekable = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,6 @@ static int demux_mf_fill_buffer(demuxer_t *demuxer)
|
||||||
demux_packet_t *dp = new_demux_packet(data.len);
|
demux_packet_t *dp = new_demux_packet(data.len);
|
||||||
memcpy(dp->buffer, data.start, data.len);
|
memcpy(dp->buffer, data.start, data.len);
|
||||||
dp->pts = mf->curr_frame / mf->sh->fps;
|
dp->pts = mf->curr_frame / mf->sh->fps;
|
||||||
dp->pos = mf->curr_frame;
|
|
||||||
dp->keyframe = true;
|
dp->keyframe = true;
|
||||||
demuxer_add_packet(demuxer, demuxer->streams[0], dp);
|
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;
|
mf->curr_frame = 0;
|
||||||
|
|
||||||
demuxer->movi_start = 0;
|
|
||||||
demuxer->movi_end = mf->nr_of_files - 1;
|
|
||||||
|
|
||||||
// create a new video stream header
|
// create a new video stream header
|
||||||
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO);
|
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO);
|
||||||
sh_video = sh->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;
|
mf->sh = sh_video;
|
||||||
demuxer->priv=(void*)mf;
|
demuxer->priv=(void*)mf;
|
||||||
|
demuxer->seekable = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -1029,7 +1029,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint64_t pos = seek->seek_position + mkv_d->segment_start;
|
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 "
|
mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] SeekHead position beyond "
|
||||||
"end of file - incomplete file?\n");
|
"end of file - incomplete file?\n");
|
||||||
continue;
|
continue;
|
||||||
|
@ -1844,14 +1844,6 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
|
||||||
|
|
||||||
display_create_tracks(demuxer);
|
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;
|
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);
|
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");
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n");
|
||||||
else {
|
else {
|
||||||
stream_t *s = demuxer->stream;
|
stream_t *s = demuxer->stream;
|
||||||
|
@ -2729,7 +2721,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
||||||
return;
|
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++)
|
for (i = 0; i < mkv_d->num_indexes; i++)
|
||||||
if (mkv_d->indexes[i].tnum == v_tnum)
|
if (mkv_d->indexes[i].tnum == v_tnum)
|
||||||
if ((index == NULL)
|
if ((index == NULL)
|
||||||
|
|
|
@ -100,9 +100,6 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
|
||||||
w->wBitsPerSample = 8 * samplesize;
|
w->wBitsPerSample = 8 * samplesize;
|
||||||
w->cbSize = 0;
|
w->cbSize = 0;
|
||||||
|
|
||||||
demuxer->movi_start = demuxer->stream->start_pos;
|
|
||||||
demuxer->movi_end = demuxer->stream->end_pos;
|
|
||||||
|
|
||||||
struct priv *p = talloc_ptrtype(demuxer, p);
|
struct priv *p = talloc_ptrtype(demuxer, p);
|
||||||
demuxer->priv = p;
|
demuxer->priv = p;
|
||||||
*p = (struct priv) {
|
*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->disp_h = height;
|
||||||
sh_video->i_bps = fps * imgsize;
|
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);
|
struct priv *p = talloc_ptrtype(demuxer, p);
|
||||||
demuxer->priv = p;
|
demuxer->priv = p;
|
||||||
*p = (struct priv) {
|
*p = (struct priv) {
|
||||||
|
@ -207,7 +201,7 @@ static int raw_fill_buffer(demuxer_t *demuxer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
struct demux_packet *dp = new_demux_packet(p->frame_size * p->read_frames);
|
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;
|
dp->pts = (dp->pos / p->frame_size) / p->frame_rate;
|
||||||
|
|
||||||
int len = stream_read(demuxer->stream, dp->buffer, dp->len);
|
int len = stream_read(demuxer->stream, dp->buffer, dp->len);
|
||||||
|
|
|
@ -1358,6 +1358,8 @@ static int d_open_file(struct demuxer *demuxer, enum demux_check check)
|
||||||
add_sub_data(demuxer, sd);
|
add_sub_data(demuxer, sd);
|
||||||
subdata_free(sd);
|
subdata_free(sd);
|
||||||
|
|
||||||
|
demuxer->seekable = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
// 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)
|
static void transfer_playlist(struct MPContext *mpctx, struct playlist *pl)
|
||||||
{
|
{
|
||||||
if (mpctx->demuxer->playlist->first) {
|
if (pl->first) {
|
||||||
playlist_transfer_entries(mpctx->playlist, mpctx->demuxer->playlist);
|
playlist_transfer_entries(mpctx->playlist, pl);
|
||||||
|
// current entry is replaced
|
||||||
if (mpctx->playlist->current)
|
if (mpctx->playlist->current)
|
||||||
playlist_remove(mpctx->playlist, mpctx->playlist->current);
|
playlist_remove(mpctx->playlist, mpctx->playlist->current);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -206,7 +206,7 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return -1 if seek failed (non-seekable stream?), 0 otherwise
|
// return -1 if seek failed (non-seekable stream?), 0 otherwise
|
||||||
static int seek(MPContext *mpctx, struct seek_params seek,
|
static int mp_seek(MPContext *mpctx, struct seek_params seek,
|
||||||
bool timeline_fallthrough)
|
bool timeline_fallthrough)
|
||||||
{
|
{
|
||||||
struct MPOpts *opts = mpctx->opts;
|
struct MPOpts *opts = mpctx->opts;
|
||||||
|
@ -215,6 +215,11 @@ static int seek(MPContext *mpctx, struct seek_params seek,
|
||||||
if (!mpctx->demuxer)
|
if (!mpctx->demuxer)
|
||||||
return -1;
|
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)
|
if (mpctx->stop_play == AT_END_OF_FILE)
|
||||||
mpctx->stop_play = KEEP_PLAYING;
|
mpctx->stop_play = KEEP_PLAYING;
|
||||||
bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts;
|
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)
|
void execute_queued_seek(struct MPContext *mpctx)
|
||||||
{
|
{
|
||||||
if (mpctx->seek.type) {
|
if (mpctx->seek.type) {
|
||||||
seek(mpctx, mpctx->seek, false);
|
mp_seek(mpctx, mpctx->seek, false);
|
||||||
mpctx->seek = (struct seek_params){0};
|
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) {
|
if (len > 0 && !demuxer->ts_resets_possible) {
|
||||||
ans = MPCLAMP((pos - start) / len, 0, 1);
|
ans = MPCLAMP((pos - start) / len, 0, 1);
|
||||||
} else {
|
} 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 ?
|
int64_t fpos = demuxer->filepos > 0 ?
|
||||||
demuxer->filepos : stream_tell(demuxer->stream);
|
demuxer->filepos : stream_tell(demuxer->stream);
|
||||||
if (size > 0)
|
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 (use_range) {
|
||||||
if (mpctx->opts->play_frames > 0)
|
if (mpctx->opts->play_frames > 0)
|
||||||
|
@ -812,7 +818,7 @@ static void handle_backstep(struct MPContext *mpctx)
|
||||||
// The whole point is getting frames _before_ that PTS,
|
// The whole point is getting frames _before_ that PTS,
|
||||||
// so apply an arbitrary offset. (In theory the offset
|
// so apply an arbitrary offset. (In theory the offset
|
||||||
// has to be large enough to reach the previous frame.)
|
// has to be large enough to reach the previous frame.)
|
||||||
seek(mpctx, (struct seek_params){
|
mp_seek(mpctx, (struct seek_params){
|
||||||
.type = MPSEEK_ABSOLUTE,
|
.type = MPSEEK_ABSOLUTE,
|
||||||
.amount = current_pts - 1.0,
|
.amount = current_pts - 1.0,
|
||||||
}, false);
|
}, false);
|
||||||
|
@ -1184,7 +1190,7 @@ void run_playloop(struct MPContext *mpctx)
|
||||||
&& (opts->gapless_audio || buffered_audio < 0.05)
|
&& (opts->gapless_audio || buffered_audio < 0.05)
|
||||||
&& (!mpctx->paused || was_restart)) {
|
&& (!mpctx->paused || was_restart)) {
|
||||||
if (end_is_chapter) {
|
if (end_is_chapter) {
|
||||||
seek(mpctx, (struct seek_params){
|
mp_seek(mpctx, (struct seek_params){
|
||||||
.type = MPSEEK_ABSOLUTE,
|
.type = MPSEEK_ABSOLUTE,
|
||||||
.amount = mpctx->timeline[mpctx->timeline_part+1].start
|
.amount = mpctx->timeline[mpctx->timeline_part+1].start
|
||||||
}, true);
|
}, true);
|
||||||
|
|
|
@ -318,8 +318,8 @@ static int open_internal(const stream_info_t *sinfo, struct stream *underlying,
|
||||||
if (s->seek && !(s->flags & MP_STREAM_SEEK))
|
if (s->seek && !(s->flags & MP_STREAM_SEEK))
|
||||||
s->flags |= MP_STREAM_SEEK;
|
s->flags |= MP_STREAM_SEEK;
|
||||||
|
|
||||||
if (s->flags & MP_STREAM_FAST_SKIPPING)
|
if (!(s->flags & MP_STREAM_SEEK))
|
||||||
s->flags |= MP_STREAM_SEEK_FW;
|
s->end_pos = 0;
|
||||||
|
|
||||||
s->uncached_type = s->type;
|
s->uncached_type = s->type;
|
||||||
|
|
||||||
|
@ -387,6 +387,8 @@ static int stream_reconnect(stream_t *s)
|
||||||
#define RECONNECT_SLEEP_MS 1000
|
#define RECONNECT_SLEEP_MS 1000
|
||||||
if (!s->streaming)
|
if (!s->streaming)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (!(s->flags & MP_STREAM_SEEK_FW))
|
||||||
|
return 0;
|
||||||
int64_t pos = s->pos;
|
int64_t pos = s->pos;
|
||||||
for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) {
|
for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) {
|
||||||
mp_msg(MSGT_STREAM, MSGL_WARN,
|
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)
|
static int stream_seek_unbuffered(stream_t *s, int64_t newpos)
|
||||||
{
|
{
|
||||||
if (newpos != s->pos) {
|
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");
|
mp_tmsg(MSGT_STREAM, MSGL_ERR, "Can not seek in this stream\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -628,7 +630,7 @@ static int stream_seek_long(stream_t *s, int64_t pos)
|
||||||
s->eof = 0;
|
s->eof = 0;
|
||||||
|
|
||||||
if (s->mode == STREAM_WRITE) {
|
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 0;
|
||||||
return 1;
|
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
|
mp_msg(MSGT_STREAM, MSGL_DBG3, "Seek from %" PRId64 " to %" PRId64
|
||||||
" (with offset %d)\n", s->pos, pos, (int)(pos - newpos));
|
" (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
|
// skipping is handled by generic code below
|
||||||
} else if (stream_seek_unbuffered(s, newpos) >= 0) {
|
} else if (stream_seek_unbuffered(s, newpos) >= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -709,6 +713,8 @@ int stream_control(stream_t *s, int cmd, void *arg)
|
||||||
|
|
||||||
void stream_update_size(stream_t *s)
|
void stream_update_size(stream_t *s)
|
||||||
{
|
{
|
||||||
|
if (!(s->flags & MP_STREAM_SEEK))
|
||||||
|
return;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
if (stream_control(s, STREAM_CTRL_GET_SIZE, &size) == STREAM_OK) {
|
if (stream_control(s, STREAM_CTRL_GET_SIZE, &size) == STREAM_OK) {
|
||||||
if (size > s->end_pos)
|
if (size > s->end_pos)
|
||||||
|
|
|
@ -47,6 +47,11 @@ int vd_control(struct sh_video *sh_video, int cmd, void *arg);
|
||||||
struct mp_hwdec_info {
|
struct mp_hwdec_info {
|
||||||
struct mp_vdpau_ctx *vdpau_ctx;
|
struct mp_vdpau_ctx *vdpau_ctx;
|
||||||
struct mp_vaapi_ctx *vaapi_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 */
|
#endif /* MPLAYER_DEC_VIDEO_H */
|
||||||
|
|
|
@ -86,6 +86,8 @@ bool hwdec_check_codec_support(const char *decoder,
|
||||||
const struct hwdec_profile_entry *table);
|
const struct hwdec_profile_entry *table);
|
||||||
int hwdec_get_max_refs(struct lavc_ctx *ctx);
|
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
|
// lavc_dr1.c
|
||||||
int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame);
|
int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame);
|
||||||
void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame);
|
void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame);
|
||||||
|
|
|
@ -421,6 +421,7 @@ static int init(struct lavc_ctx *ctx)
|
||||||
static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
|
static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
|
||||||
const char *decoder)
|
const char *decoder)
|
||||||
{
|
{
|
||||||
|
hwdec_request_api(info, "vaapi");
|
||||||
if (!info || !info->vaapi_ctx)
|
if (!info || !info->vaapi_ctx)
|
||||||
return HWDEC_ERR_NO_CTX;
|
return HWDEC_ERR_NO_CTX;
|
||||||
if (!hwdec_check_codec_support(decoder, profiles))
|
if (!hwdec_check_codec_support(decoder, profiles))
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "video/img_format.h"
|
#include "video/img_format.h"
|
||||||
#include "video/mp_image_pool.h"
|
#include "video/mp_image_pool.h"
|
||||||
#include "video/filter/vf.h"
|
#include "video/filter/vf.h"
|
||||||
|
#include "video/decode/dec_video.h"
|
||||||
#include "demux/stheader.h"
|
#include "demux/stheader.h"
|
||||||
#include "demux/demux_packet.h"
|
#include "demux/demux_packet.h"
|
||||||
#include "osdep/numcores.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;
|
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,
|
static int hwdec_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
|
||||||
const char *decoder, const char **hw_decoder)
|
const char *decoder, const char **hw_decoder)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
#include "memcpy_pic.h"
|
#include "memcpy_pic.h"
|
||||||
#include "fmt-conversion.h"
|
#include "fmt-conversion.h"
|
||||||
|
|
||||||
|
#include "video/filter/vf.h"
|
||||||
|
|
||||||
#if HAVE_PTHREADS
|
#if HAVE_PTHREADS
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
static pthread_mutex_t refcount_mutex = PTHREAD_MUTEX_INITIALIZER;
|
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;
|
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,
|
void mp_image_set_colorspace_details(struct mp_image *image,
|
||||||
struct mp_csp_details *csp)
|
struct mp_csp_details *csp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -153,6 +153,9 @@ void mp_image_params_from_image(struct mp_image_params *params,
|
||||||
void mp_image_set_params(struct mp_image *image,
|
void mp_image_set_params(struct mp_image *image,
|
||||||
const struct mp_image_params *params);
|
const struct mp_image_params *params);
|
||||||
|
|
||||||
|
void mp_image_set_attributes(struct mp_image *image,
|
||||||
|
const struct mp_image_params *params);
|
||||||
|
|
||||||
struct AVFrame;
|
struct AVFrame;
|
||||||
void mp_image_copy_fields_from_av_frame(struct mp_image *dst,
|
void mp_image_copy_fields_from_av_frame(struct mp_image *dst,
|
||||||
struct AVFrame *src);
|
struct AVFrame *src);
|
||||||
|
|
|
@ -1008,3 +1008,12 @@ void mp_log_source(struct mp_log *log, int lev, const char *src)
|
||||||
src = next;
|
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
|
||||||
|
};
|
||||||
|
|
|
@ -164,6 +164,45 @@ void mpgl_set_backend_w32(MPGLContext *ctx);
|
||||||
void mpgl_set_backend_x11(MPGLContext *ctx);
|
void mpgl_set_backend_x11(MPGLContext *ctx);
|
||||||
void mpgl_set_backend_wayland(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 *mp_getdladdr(const char *s);
|
||||||
|
|
||||||
void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
|
void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
|
||||||
|
|
|
@ -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
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include <va/va_glx.h>
|
||||||
|
|
||||||
|
#include "x11_common.h"
|
||||||
|
#include "gl_common.h"
|
||||||
|
#include "video/vaapi.h"
|
||||||
|
#include "video/decode/dec_video.h"
|
||||||
|
|
||||||
|
struct priv {
|
||||||
|
struct mp_vaapi_ctx *ctx;
|
||||||
|
VADisplay *display;
|
||||||
|
GLuint gl_texture;
|
||||||
|
void *vaglx_surface;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool query_format(int imgfmt)
|
||||||
|
{
|
||||||
|
return imgfmt == IMGFMT_VAAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_texture(struct gl_hwdec *hw)
|
||||||
|
{
|
||||||
|
struct priv *p = hw->priv;
|
||||||
|
VAStatus status;
|
||||||
|
|
||||||
|
if (p->vaglx_surface) {
|
||||||
|
status = vaDestroySurfaceGLX(p->display, p->vaglx_surface);
|
||||||
|
check_va_status(status, "vaDestroySurfaceGLX()");
|
||||||
|
p->vaglx_surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
glDeleteTextures(1, &p->gl_texture);
|
||||||
|
p->gl_texture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct gl_hwdec *hw)
|
||||||
|
{
|
||||||
|
struct priv *p = hw->priv;
|
||||||
|
destroy_texture(hw);
|
||||||
|
va_destroy(p->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct gl_hwdec *hw)
|
||||||
|
{
|
||||||
|
if (hw->info->vaapi_ctx)
|
||||||
|
return -1;
|
||||||
|
if (!hw->mpgl->vo->x11 || !glXGetCurrentContext())
|
||||||
|
return -1;
|
||||||
|
struct priv *p = talloc_zero(hw, struct priv);
|
||||||
|
hw->priv = p;
|
||||||
|
p->display = vaGetDisplayGLX(hw->mpgl->vo->x11->display);
|
||||||
|
if (!p->display)
|
||||||
|
return -1;
|
||||||
|
p->ctx = va_initialize(p->display);
|
||||||
|
if (!p->ctx) {
|
||||||
|
vaTerminate(p->display);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
hw->info->vaapi_ctx = p->ctx;
|
||||||
|
hw->converted_imgfmt = IMGFMT_RGBA;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int reinit(struct gl_hwdec *hw, int w, int h)
|
||||||
|
{
|
||||||
|
struct priv *p = hw->priv;
|
||||||
|
GL *gl = hw->mpgl->gl;
|
||||||
|
VAStatus status;
|
||||||
|
|
||||||
|
destroy_texture(hw);
|
||||||
|
|
||||||
|
gl->GenTextures(1, &p->gl_texture);
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D, p->gl_texture);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
status = vaCreateSurfaceGLX(p->display, GL_TEXTURE_2D,
|
||||||
|
p->gl_texture, &p->vaglx_surface);
|
||||||
|
return check_va_status(status, "vaCreateSurfaceGLX()") ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int load_image(struct gl_hwdec *hw, struct mp_image *hw_image,
|
||||||
|
GLuint *out_textures)
|
||||||
|
{
|
||||||
|
struct priv *p = hw->priv;
|
||||||
|
VAStatus status;
|
||||||
|
|
||||||
|
if (!p->vaglx_surface)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
status = vaCopySurfaceGLX(p->display, p->vaglx_surface,
|
||||||
|
va_surface_id_in_mp_image(hw_image),
|
||||||
|
va_get_colorspace_flag(hw_image->colorspace));
|
||||||
|
if (!check_va_status(status, "vaCopySurfaceGLX()"))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
out_textures[0] = p->gl_texture;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unload_image(struct gl_hwdec *hw)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct gl_hwdec_driver gl_hwdec_vaglx = {
|
||||||
|
.api_name = "vaapi",
|
||||||
|
.query_format = query_format,
|
||||||
|
.create = create,
|
||||||
|
.reinit = reinit,
|
||||||
|
.load_image = load_image,
|
||||||
|
.unload_image = unload_image,
|
||||||
|
.destroy = destroy,
|
||||||
|
};
|
|
@ -114,6 +114,7 @@ struct texplane {
|
||||||
struct video_image {
|
struct video_image {
|
||||||
struct texplane planes[4];
|
struct texplane planes[4];
|
||||||
bool image_flipped;
|
bool image_flipped;
|
||||||
|
struct mp_image *hwimage; // if hw decoding is active
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scaler {
|
struct scaler {
|
||||||
|
@ -202,6 +203,9 @@ struct gl_video {
|
||||||
int last_dither_matrix_size;
|
int last_dither_matrix_size;
|
||||||
float *last_dither_matrix;
|
float *last_dither_matrix;
|
||||||
|
|
||||||
|
struct gl_hwdec *hwdec;
|
||||||
|
bool hwdec_active;
|
||||||
|
|
||||||
void *scratch;
|
void *scratch;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1129,7 +1133,7 @@ static void reinit_rendering(struct gl_video *p)
|
||||||
|
|
||||||
uninit_rendering(p);
|
uninit_rendering(p);
|
||||||
|
|
||||||
if (!p->image.planes[0].gl_texture)
|
if (!p->image_format)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int n = 0; n < 2; n++)
|
for (int n = 0; n < 2; n++)
|
||||||
|
@ -1196,17 +1200,41 @@ void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d)
|
||||||
debug_check_gl(p, "after 3d lut creation");
|
debug_check_gl(p, "after 3d lut creation");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_image_textures(struct gl_video *p, struct video_image *vimg)
|
static void set_image_textures(struct gl_video *p, struct video_image *vimg,
|
||||||
|
GLuint imgtex[4])
|
||||||
|
{
|
||||||
|
GL *gl = p->gl;
|
||||||
|
GLuint dummy[4];
|
||||||
|
if (!imgtex)
|
||||||
|
imgtex = dummy;
|
||||||
|
|
||||||
|
if (p->hwdec_active) {
|
||||||
|
assert(vimg->hwimage);
|
||||||
|
p->hwdec->driver->load_image(p->hwdec, vimg->hwimage, imgtex);
|
||||||
|
} else {
|
||||||
|
for (int n = 0; n < p->plane_count; n++)
|
||||||
|
imgtex[n] = vimg->planes[n].gl_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int n = 0; n < 4; n++) {
|
||||||
|
gl->ActiveTexture(GL_TEXTURE0 + n);
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D, imgtex[n]);
|
||||||
|
}
|
||||||
|
gl->ActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unset_image_textures(struct gl_video *p)
|
||||||
{
|
{
|
||||||
GL *gl = p->gl;
|
GL *gl = p->gl;
|
||||||
|
|
||||||
for (int n = 0; n < p->plane_count; n++) {
|
for (int n = 0; n < 4; n++) {
|
||||||
struct texplane *plane = &vimg->planes[n];
|
|
||||||
|
|
||||||
gl->ActiveTexture(GL_TEXTURE0 + n);
|
gl->ActiveTexture(GL_TEXTURE0 + n);
|
||||||
gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
|
gl->BindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
gl->ActiveTexture(GL_TEXTURE0);
|
gl->ActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
if (p->hwdec_active)
|
||||||
|
p->hwdec->driver->unload_image(p->hwdec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_video(struct gl_video *p)
|
static void init_video(struct gl_video *p)
|
||||||
|
@ -1243,12 +1271,14 @@ static void init_video(struct gl_video *p)
|
||||||
plane->w = full_w >> p->image_desc.xs[n];
|
plane->w = full_w >> p->image_desc.xs[n];
|
||||||
plane->h = full_h >> p->image_desc.ys[n];
|
plane->h = full_h >> p->image_desc.ys[n];
|
||||||
|
|
||||||
|
if (p->hwdec_active) {
|
||||||
|
// We expect hwdec backends to allocate exact size
|
||||||
|
plane->tex_w = plane->w;
|
||||||
|
plane->tex_h = plane->h;
|
||||||
|
} else {
|
||||||
texture_size(p, plane->w, plane->h,
|
texture_size(p, plane->w, plane->h,
|
||||||
&plane->tex_w, &plane->tex_h);
|
&plane->tex_w, &plane->tex_h);
|
||||||
|
|
||||||
MP_VERBOSE(p, "Texture for plane %d: %dx%d\n",
|
|
||||||
n, plane->tex_w, plane->tex_h);
|
|
||||||
|
|
||||||
gl->ActiveTexture(GL_TEXTURE0 + n);
|
gl->ActiveTexture(GL_TEXTURE0 + n);
|
||||||
gl->GenTextures(1, &plane->gl_texture);
|
gl->GenTextures(1, &plane->gl_texture);
|
||||||
gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
|
gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
|
||||||
|
@ -1259,6 +1289,10 @@ static void init_video(struct gl_video *p)
|
||||||
|
|
||||||
default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR);
|
default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MP_VERBOSE(p, "Texture for plane %d: %dx%d\n",
|
||||||
|
n, plane->tex_w, plane->tex_h);
|
||||||
|
}
|
||||||
gl->ActiveTexture(GL_TEXTURE0);
|
gl->ActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
p->texture_w = p->image.planes[0].tex_w;
|
p->texture_w = p->image.planes[0].tex_w;
|
||||||
|
@ -1266,6 +1300,11 @@ static void init_video(struct gl_video *p)
|
||||||
|
|
||||||
debug_check_gl(p, "after video texture creation");
|
debug_check_gl(p, "after video texture creation");
|
||||||
|
|
||||||
|
if (p->hwdec_active) {
|
||||||
|
if (p->hwdec->driver->reinit(p->hwdec, p->image_w, p->image_h) < 0)
|
||||||
|
MP_ERR(p, "Initializing hardware ddecoding video texture failed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
reinit_rendering(p);
|
reinit_rendering(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1287,6 +1326,7 @@ static void uninit_video(struct gl_video *p)
|
||||||
plane->buffer_ptr = NULL;
|
plane->buffer_ptr = NULL;
|
||||||
plane->buffer_size = 0;
|
plane->buffer_size = 0;
|
||||||
}
|
}
|
||||||
|
mp_image_unrefp(&vimg->hwimage);
|
||||||
|
|
||||||
fbotex_uninit(p, &p->indirect_fbo);
|
fbotex_uninit(p, &p->indirect_fbo);
|
||||||
fbotex_uninit(p, &p->scale_sep_fbo);
|
fbotex_uninit(p, &p->scale_sep_fbo);
|
||||||
|
@ -1373,14 +1413,15 @@ void gl_video_render_frame(struct gl_video *p)
|
||||||
// Order of processing:
|
// Order of processing:
|
||||||
// [indirect -> [scale_sep ->]] final
|
// [indirect -> [scale_sep ->]] final
|
||||||
|
|
||||||
set_image_textures(p, vimg);
|
GLuint imgtex[4] = {0};
|
||||||
|
set_image_textures(p, vimg, imgtex);
|
||||||
|
|
||||||
struct fbotex chain = {
|
struct fbotex chain = {
|
||||||
.vp_w = p->image_w,
|
.vp_w = p->image_w,
|
||||||
.vp_h = p->image_h,
|
.vp_h = p->image_h,
|
||||||
.tex_w = p->texture_w,
|
.tex_w = p->texture_w,
|
||||||
.tex_h = p->texture_h,
|
.tex_h = p->texture_h,
|
||||||
.texture = vimg->planes[0].gl_texture,
|
.texture = imgtex[0],
|
||||||
};
|
};
|
||||||
|
|
||||||
handle_pass(p, &chain, &p->indirect_fbo, p->indirect_program);
|
handle_pass(p, &chain, &p->indirect_fbo, p->indirect_program);
|
||||||
|
@ -1441,6 +1482,8 @@ void gl_video_render_frame(struct gl_video *p)
|
||||||
|
|
||||||
gl->UseProgram(0);
|
gl->UseProgram(0);
|
||||||
|
|
||||||
|
unset_image_textures(p);
|
||||||
|
|
||||||
p->frames_rendered++;
|
p->frames_rendered++;
|
||||||
|
|
||||||
debug_check_gl(p, "after video rendering");
|
debug_check_gl(p, "after video rendering");
|
||||||
|
@ -1552,16 +1595,21 @@ static bool get_image(struct gl_video *p, struct mp_image *mpi)
|
||||||
void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
|
void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
|
||||||
{
|
{
|
||||||
GL *gl = p->gl;
|
GL *gl = p->gl;
|
||||||
int n;
|
|
||||||
|
|
||||||
assert(mpi->num_planes == p->plane_count);
|
|
||||||
|
|
||||||
struct video_image *vimg = &p->image;
|
struct video_image *vimg = &p->image;
|
||||||
|
|
||||||
|
if (p->hwdec_active) {
|
||||||
|
mp_image_setrefp(&vimg->hwimage, mpi);
|
||||||
|
p->have_image = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mpi->num_planes == p->plane_count);
|
||||||
|
|
||||||
mp_image_t mpi2 = *mpi;
|
mp_image_t mpi2 = *mpi;
|
||||||
bool pbo = false;
|
bool pbo = false;
|
||||||
if (!vimg->planes[0].buffer_ptr && get_image(p, &mpi2)) {
|
if (!vimg->planes[0].buffer_ptr && get_image(p, &mpi2)) {
|
||||||
for (n = 0; n < p->plane_count; n++) {
|
for (int n = 0; n < p->plane_count; n++) {
|
||||||
int line_bytes = mpi->plane_w[n] * p->image_desc.bytes[n];
|
int line_bytes = mpi->plane_w[n] * p->image_desc.bytes[n];
|
||||||
memcpy_pic(mpi2.planes[n], mpi->planes[n], line_bytes, mpi->plane_h[n],
|
memcpy_pic(mpi2.planes[n], mpi->planes[n], line_bytes, mpi->plane_h[n],
|
||||||
mpi2.stride[n], mpi->stride[n]);
|
mpi2.stride[n], mpi->stride[n]);
|
||||||
|
@ -1570,7 +1618,7 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
|
||||||
pbo = true;
|
pbo = true;
|
||||||
}
|
}
|
||||||
vimg->image_flipped = mpi->stride[0] < 0;
|
vimg->image_flipped = mpi->stride[0] < 0;
|
||||||
for (n = 0; n < p->plane_count; n++) {
|
for (int n = 0; n < p->plane_count; n++) {
|
||||||
struct texplane *plane = &vimg->planes[n];
|
struct texplane *plane = &vimg->planes[n];
|
||||||
void *plane_ptr = mpi->planes[n];
|
void *plane_ptr = mpi->planes[n];
|
||||||
if (pbo) {
|
if (pbo) {
|
||||||
|
@ -1598,10 +1646,11 @@ struct mp_image *gl_video_download_image(struct gl_video *p)
|
||||||
|
|
||||||
struct video_image *vimg = &p->image;
|
struct video_image *vimg = &p->image;
|
||||||
|
|
||||||
if (!p->have_image || !vimg->planes[0].gl_texture)
|
if (!p->have_image)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
assert(p->image_format == p->image_params.imgfmt);
|
set_image_textures(p, vimg, NULL);
|
||||||
|
|
||||||
assert(p->texture_w >= p->image_params.w);
|
assert(p->texture_w >= p->image_params.w);
|
||||||
assert(p->texture_h >= p->image_params.h);
|
assert(p->texture_h >= p->image_params.h);
|
||||||
|
|
||||||
|
@ -1611,12 +1660,12 @@ struct mp_image *gl_video_download_image(struct gl_video *p)
|
||||||
for (int n = 0; n < p->plane_count; n++) {
|
for (int n = 0; n < p->plane_count; n++) {
|
||||||
struct texplane *plane = &vimg->planes[n];
|
struct texplane *plane = &vimg->planes[n];
|
||||||
gl->ActiveTexture(GL_TEXTURE0 + n);
|
gl->ActiveTexture(GL_TEXTURE0 + n);
|
||||||
gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
|
|
||||||
glDownloadTex(gl, GL_TEXTURE_2D, plane->gl_format, plane->gl_type,
|
glDownloadTex(gl, GL_TEXTURE_2D, plane->gl_format, plane->gl_type,
|
||||||
image->planes[n], image->stride[n]);
|
image->planes[n], image->stride[n]);
|
||||||
}
|
}
|
||||||
gl->ActiveTexture(GL_TEXTURE0);
|
mp_image_set_attributes(image, &p->image_params);
|
||||||
mp_image_set_params(image, &p->image_params);
|
|
||||||
|
unset_image_textures(p);
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -1884,6 +1933,12 @@ static bool init_format(int fmt, struct gl_video *init)
|
||||||
if (!init)
|
if (!init)
|
||||||
init = &dummy;
|
init = &dummy;
|
||||||
|
|
||||||
|
init->hwdec_active = false;
|
||||||
|
if (init->hwdec && init->hwdec->driver->query_format(fmt)) {
|
||||||
|
fmt = init->hwdec->converted_imgfmt;
|
||||||
|
init->hwdec_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(fmt);
|
struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(fmt);
|
||||||
if (!desc.id)
|
if (!desc.id)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1985,9 +2040,10 @@ static bool init_format(int fmt, struct gl_video *init)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gl_video_check_format(int mp_format)
|
bool gl_video_check_format(struct gl_video *p, int mp_format)
|
||||||
{
|
{
|
||||||
return init_format(mp_format, NULL);
|
struct gl_video tmp = *p;
|
||||||
|
return init_format(mp_format, &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_video_config(struct gl_video *p, struct mp_image_params *params)
|
void gl_video_config(struct gl_video *p, struct mp_image_params *params)
|
||||||
|
@ -2012,6 +2068,7 @@ void gl_video_config(struct gl_video *p, struct mp_image_params *params)
|
||||||
p->colorspace = csp;
|
p->colorspace = csp;
|
||||||
|
|
||||||
p->have_image = false;
|
p->have_image = false;
|
||||||
|
mp_image_unrefp(&p->image.hwimage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b)
|
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b)
|
||||||
|
@ -2132,3 +2189,9 @@ void gl_video_resize_redraw(struct gl_video *p, int w, int h)
|
||||||
gl_video_render_frame(p);
|
gl_video_render_frame(p);
|
||||||
mpgl_osd_redraw_cb(p->osd, draw_osd_cb, p);
|
mpgl_osd_redraw_cb(p->osd, draw_osd_cb, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec)
|
||||||
|
{
|
||||||
|
p->hwdec = hwdec;
|
||||||
|
mp_image_unrefp(&p->image.hwimage);
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ struct gl_video;
|
||||||
struct gl_video *gl_video_init(GL *gl, struct mp_log *log);
|
struct gl_video *gl_video_init(GL *gl, struct mp_log *log);
|
||||||
void gl_video_uninit(struct gl_video *p);
|
void gl_video_uninit(struct gl_video *p);
|
||||||
void gl_video_set_options(struct gl_video *p, struct gl_video_opts *opts);
|
void gl_video_set_options(struct gl_video *p, struct gl_video_opts *opts);
|
||||||
|
bool gl_video_check_format(struct gl_video *p, int mp_format);
|
||||||
void gl_video_config(struct gl_video *p, struct mp_image_params *params);
|
void gl_video_config(struct gl_video *p, struct mp_image_params *params);
|
||||||
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
|
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
|
||||||
void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d);
|
void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d);
|
||||||
|
@ -73,6 +74,7 @@ bool gl_video_get_equalizer(struct gl_video *p, const char *name, int *val);
|
||||||
void gl_video_set_debug(struct gl_video *p, bool enable);
|
void gl_video_set_debug(struct gl_video *p, bool enable);
|
||||||
void gl_video_resize_redraw(struct gl_video *p, int w, int h);
|
void gl_video_resize_redraw(struct gl_video *p, int w, int h);
|
||||||
|
|
||||||
bool gl_video_check_format(int mp_format);
|
struct gl_hwdec;
|
||||||
|
void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "gl_osd.h"
|
#include "gl_osd.h"
|
||||||
#include "filter_kernels.h"
|
#include "filter_kernels.h"
|
||||||
#include "video/memcpy_pic.h"
|
#include "video/memcpy_pic.h"
|
||||||
|
#include "video/decode/dec_video.h"
|
||||||
#include "gl_video.h"
|
#include "gl_video.h"
|
||||||
#include "gl_lcms.h"
|
#include "gl_lcms.h"
|
||||||
|
|
||||||
|
@ -58,6 +59,8 @@ struct gl_priv {
|
||||||
|
|
||||||
struct gl_video *renderer;
|
struct gl_video *renderer;
|
||||||
|
|
||||||
|
struct gl_hwdec *hwdec;
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
struct gl_video_opts *renderer_opts;
|
struct gl_video_opts *renderer_opts;
|
||||||
struct mp_icc_opts *icc_opts;
|
struct mp_icc_opts *icc_opts;
|
||||||
|
@ -134,8 +137,9 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
|
||||||
|
|
||||||
static int query_format(struct vo *vo, uint32_t format)
|
static int query_format(struct vo *vo, uint32_t format)
|
||||||
{
|
{
|
||||||
|
struct gl_priv *p = vo->priv;
|
||||||
int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP;
|
int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP;
|
||||||
if (!gl_video_check_format(format))
|
if (!gl_video_check_format(p->renderer, format))
|
||||||
return 0;
|
return 0;
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
|
@ -191,6 +195,68 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void load_hwdec_driver(struct gl_priv *p,
|
||||||
|
const struct gl_hwdec_driver *drv)
|
||||||
|
{
|
||||||
|
assert(!p->hwdec);
|
||||||
|
struct gl_hwdec *hwdec = talloc(NULL, struct gl_hwdec);
|
||||||
|
*hwdec = (struct gl_hwdec) {
|
||||||
|
.driver = drv,
|
||||||
|
.log = mp_log_new(hwdec, p->vo->log, drv->api_name),
|
||||||
|
.mpgl = p->glctx,
|
||||||
|
.info = talloc_zero(hwdec, struct mp_hwdec_info),
|
||||||
|
};
|
||||||
|
mpgl_lock(p->glctx);
|
||||||
|
if (hwdec->driver->create(hwdec) < 0) {
|
||||||
|
mpgl_unlock(p->glctx);
|
||||||
|
talloc_free(hwdec);
|
||||||
|
MP_ERR(p->vo, "Couldn't load hwdec driver '%s'\n", drv->api_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p->hwdec = hwdec;
|
||||||
|
gl_video_set_hwdec(p->renderer, p->hwdec);
|
||||||
|
mpgl_unlock(p->glctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void request_hwdec_api(struct mp_hwdec_info *info, const char *api_name)
|
||||||
|
{
|
||||||
|
struct gl_priv *p = info->load_api_ctx;
|
||||||
|
// Load at most one hwdec API
|
||||||
|
if (p->hwdec)
|
||||||
|
return;
|
||||||
|
for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
|
||||||
|
const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n];
|
||||||
|
if (api_name && strcmp(drv->api_name, api_name) == 0) {
|
||||||
|
load_hwdec_driver(p, drv);
|
||||||
|
if (p->hwdec) {
|
||||||
|
*info = *p->hwdec->info;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_hwdec_info(struct gl_priv *p, struct mp_hwdec_info *info)
|
||||||
|
{
|
||||||
|
info->load_api = request_hwdec_api;
|
||||||
|
info->load_api_ctx = p;
|
||||||
|
if (p->hwdec)
|
||||||
|
*info = *p->hwdec->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unload_hwdec_driver(struct gl_priv *p)
|
||||||
|
{
|
||||||
|
if (p->hwdec) {
|
||||||
|
mpgl_lock(p->glctx);
|
||||||
|
gl_video_set_hwdec(p->renderer, NULL);
|
||||||
|
p->hwdec->driver->destroy(p->hwdec);
|
||||||
|
talloc_free(p->hwdec);
|
||||||
|
p->hwdec = NULL;
|
||||||
|
mpgl_unlock(p->glctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool reparse_cmdline(struct gl_priv *p, char *args)
|
static bool reparse_cmdline(struct gl_priv *p, char *args)
|
||||||
{
|
{
|
||||||
struct m_config *cfg = NULL;
|
struct m_config *cfg = NULL;
|
||||||
|
@ -263,6 +329,10 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||||
mpgl_unlock(p->glctx);
|
mpgl_unlock(p->glctx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case VOCTRL_GET_HWDEC_INFO: {
|
||||||
|
get_hwdec_info(p, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
case VOCTRL_REDRAW_FRAME:
|
case VOCTRL_REDRAW_FRAME:
|
||||||
mpgl_lock(p->glctx);
|
mpgl_lock(p->glctx);
|
||||||
gl_video_render_frame(p->renderer);
|
gl_video_render_frame(p->renderer);
|
||||||
|
@ -291,6 +361,7 @@ static void uninit(struct vo *vo)
|
||||||
struct gl_priv *p = vo->priv;
|
struct gl_priv *p = vo->priv;
|
||||||
|
|
||||||
if (p->glctx) {
|
if (p->glctx) {
|
||||||
|
unload_hwdec_driver(p);
|
||||||
if (p->renderer)
|
if (p->renderer)
|
||||||
gl_video_uninit(p->renderer);
|
gl_video_uninit(p->renderer);
|
||||||
mpgl_uninit(p->glctx);
|
mpgl_uninit(p->glctx);
|
||||||
|
|
Loading…
Reference in New Issue