aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rwxr-xr-xconfigure20
-rw-r--r--core/mplayer.c7
-rw-r--r--demux/stheader.h3
-rw-r--r--video/decode/dec_video.h6
-rw-r--r--video/decode/lavc.h19
-rw-r--r--video/decode/lavc_dr1.c2
-rw-r--r--video/decode/vd_lavc.c138
-rw-r--r--video/decode/vdpau.c228
-rw-r--r--video/decode/vdpau_old.c267
-rw-r--r--video/filter/vf.h2
-rw-r--r--video/filter/vf_vo.c4
-rw-r--r--video/fmt-conversion.c6
-rw-r--r--video/img_format.c1
-rw-r--r--video/img_format.h5
-rw-r--r--video/out/vo.h3
-rw-r--r--video/out/vo_vdpau.c372
-rw-r--r--video/vdpau.c73
-rw-r--r--video/vdpau.h55
19 files changed, 897 insertions, 318 deletions
diff --git a/Makefile b/Makefile
index 92ef2c7cf5..4491571255 100644
--- a/Makefile
+++ b/Makefile
@@ -106,7 +106,9 @@ SOURCES-$(OSS) += audio/out/ao_oss.c
SOURCES-$(PULSE) += audio/out/ao_pulse.c
SOURCES-$(PORTAUDIO) += audio/out/ao_portaudio.c
SOURCES-$(RSOUND) += audio/out/ao_rsound.c
-SOURCES-$(VDPAU) += video/out/vo_vdpau.c
+SOURCES-$(VDPAU) += video/vdpau.c video/out/vo_vdpau.c
+SOURCES-$(VDPAU_DEC) += video/decode/vdpau.c
+SOURCES-$(VDPAU_DEC_OLD) += video/decode/vdpau_old.c
SOURCES-$(X11) += video/out/vo_x11.c video/out/x11_common.c
SOURCES-$(XV) += video/out/vo_xv.c
diff --git a/configure b/configure
index c108064ee8..4bf7e271f8 100755
--- a/configure
+++ b/configure
@@ -2635,6 +2635,23 @@ else
def_avresample_has_set_channel_mapping='#define HAVE_AVRESAMPLE_SET_CHANNEL_MAPPING 0'
fi
+_vdpau_dec=no
+_vdpau_dec_old=no
+if test "$_vdpau" = yes ; then
+
+echocheck "libavcodec new vdpau API"
+_avcodec_new_vdpau_api=no
+statement_check libavutil/pixfmt.h 'int x = AV_PIX_FMT_VDPAU' && _avcodec_new_vdpau_api=yes
+if test "$_avcodec_new_vdpau_api" = yes ; then
+ def_avcodec_new_vdpau_api='#define HAVE_AV_CODEC_NEW_VDPAU_API 1'
+ _vdpau_dec=yes
+else
+ def_avcodec_new_vdpau_api='#define HAVE_AV_CODEC_NEW_VDPAU_API 0'
+ _vdpau_dec_old=yes
+fi
+echores "$_avcodec_new_vdpau_api"
+
+fi
echocheck "libavcodec AV_CODEC_PROP_TEXT_SUB API"
_avcodec_has_text_flag_api=no
@@ -3077,6 +3094,8 @@ TV = $_tv
TV_V4L2 = $_tv_v4l2
VCD = $_vcd
VDPAU = $_vdpau
+VDPAU_DEC = $_vdpau_dec
+VDPAU_DEC_OLD = $_vdpau_dec_old
WIN32 = $_win32
X11 = $_x11
WAYLAND = $_wayland
@@ -3179,6 +3198,7 @@ $def_zlib
$def_avutil_has_refcounting
$def_avutil_has_qp_api
+$def_avcodec_new_vdpau_api
$def_avcodec_has_text_flag_api
$def_avcodec_has_chroma_pos_api
$def_libpostproc
diff --git a/core/mplayer.c b/core/mplayer.c
index 44cc3f5540..4ccfc6f526 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -2319,7 +2319,7 @@ int reinit_video_chain(struct MPContext *mpctx)
struct MPOpts *opts = mpctx->opts;
assert(!(mpctx->initialized_flags & INITIALIZED_VCODEC));
init_demux_stream(mpctx, STREAM_VIDEO);
- sh_video_t * const sh_video = mpctx->sh_video;
+ sh_video_t *sh_video = mpctx->sh_video;
if (!sh_video) {
uninit_player(mpctx, INITIALIZED_VO);
goto no_video;
@@ -2354,6 +2354,11 @@ int reinit_video_chain(struct MPContext *mpctx)
&(bool){false});
}
mpctx->initialized_flags |= INITIALIZED_VO;
+
+ // dynamic allocation only to make stheader.h lighter
+ talloc_free(sh_video->hwdec_info);
+ sh_video->hwdec_info = talloc_zero(sh_video, struct mp_hwdec_info);
+ vo_control(mpctx->video_out, VOCTRL_GET_HWDEC_INFO, sh_video->hwdec_info);
}
vo_update_window_title(mpctx);
diff --git a/demux/stheader.h b/demux/stheader.h
index e90909e17a..6109221442 100644
--- a/demux/stheader.h
+++ b/demux/stheader.h
@@ -127,11 +127,12 @@ typedef struct sh_video {
float stream_aspect; // aspect ratio in media headers (DVD IFO files)
int i_bps; // == bitrate (compressed bytes/sec)
int disp_w, disp_h; // display size (filled by demuxer or decoder)
- struct mp_image_params *vf_input; // video filter input params
// output driver/filters: (set by libmpcodecs core)
struct vf_instance *vfilter; // video filter chain
const struct vd_functions *vd_driver;
int vf_initialized; // -1 failed, 0 not done, 1 done
+ struct mp_image_params *vf_input; // video filter input params
+ struct mp_hwdec_info *hwdec_info; // video output hwdec handles
// win32-compatible codec parameters:
BITMAPINFOHEADER *bih;
} sh_video_t;
diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h
index 141442fa19..4ba052afd1 100644
--- a/video/decode/dec_video.h
+++ b/video/decode/dec_video.h
@@ -47,4 +47,10 @@ int vd_control(struct sh_video *sh_video, int cmd, void *arg);
extern int divx_quality;
+// Used to communicate hardware decoder API handles from VO to video decoder.
+// The VO can set the context pointer for supported APIs.
+struct mp_hwdec_info {
+ struct mp_vdpau_ctx *vdpau_ctx;
+};
+
#endif /* MPLAYER_DEC_VIDEO_H */
diff --git a/video/decode/lavc.h b/video/decode/lavc.h
index 25ed2b8ac5..3611530400 100644
--- a/video/decode/lavc.h
+++ b/video/decode/lavc.h
@@ -10,7 +10,7 @@
#include "demux/stheader.h"
#include "video/mp_image.h"
-typedef struct ffmpeg_ctx {
+typedef struct lavc_ctx {
AVCodecContext *avctx;
AVFrame *pic;
struct hwdec *hwdec;
@@ -23,11 +23,28 @@ typedef struct ffmpeg_ctx {
enum AVDiscard skip_frame;
const char *software_fallback_decoder;
+ // From VO
+ struct mp_hwdec_info *hwdec_info;
+
+ // For free use by hwdec implementation
+ void *hwdec_priv;
+
+ // Legacy
bool do_dr1;
struct FramePool *dr1_buffer_pool;
struct mp_image_pool *non_dr1_pool;
} vd_ffmpeg_ctx;
+struct vd_lavc_hwdec_functions {
+ // If not-NULL, a 0 terminated list of IMGFMT_ formats. Only one of these
+ // formats is accepted when handling the libavcodec get_format callback.
+ const int *image_formats;
+ int (*init)(struct lavc_ctx *ctx);
+ void (*uninit)(struct lavc_ctx *ctx);
+ struct mp_image *(*allocate_image)(struct lavc_ctx *ctx, AVFrame *frame);
+ void (*fix_image)(struct lavc_ctx *ctx, struct mp_image *img);
+};
+
// 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/lavc_dr1.c b/video/decode/lavc_dr1.c
index 5dc73c3ea8..15fc44a445 100644
--- a/video/decode/lavc_dr1.c
+++ b/video/decode/lavc_dr1.c
@@ -137,7 +137,7 @@ static int alloc_buffer(FramePool *pool, AVCodecContext *s)
int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame)
{
sh_video_t *sh = s->opaque;
- struct ffmpeg_ctx *ctx = sh->context;
+ struct lavc_ctx *ctx = sh->context;
if (!ctx->dr1_buffer_pool) {
ctx->dr1_buffer_pool = av_mallocz(sizeof(*ctx->dr1_buffer_pool));
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 3ee1b40bb8..ea12126ffb 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -34,6 +34,7 @@
#include "config.h"
#include "core/mp_msg.h"
#include "core/options.h"
+#include "core/bstr.h"
#include "core/av_opts.h"
#include "core/av_common.h"
#include "core/codecs.h"
@@ -50,7 +51,6 @@
#include "osdep/numcores.h"
#include "video/csputils.h"
-#include "libavcodec/avcodec.h"
#include "lavc.h"
#if AVPALETTE_SIZE != MP_PALETTE_SIZE
@@ -62,8 +62,6 @@
static void init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec);
static void uninit_avctx(sh_video_t *sh);
static void setup_refcounting_hw(struct AVCodecContext *s);
-static void draw_slice_hwdec(struct AVCodecContext *s, const AVFrame *src,
- int offset[4], int y, int type, int height);
static enum PixelFormat get_format_hwdec(struct AVCodecContext *avctx,
const enum PixelFormat *pix_fmt);
@@ -94,17 +92,32 @@ enum hwdec_type {
struct hwdec {
enum hwdec_type api;
const char *codec, *hw_codec;
+ const struct vd_lavc_hwdec_functions *fns;
};
+const struct vd_lavc_hwdec_functions mp_vd_lavc_vdpau;
+const struct vd_lavc_hwdec_functions mp_vd_lavc_vdpau_old;
+
static const struct hwdec hwdec_list[] = {
- {HWDEC_VDPAU, "h264", "h264_vdpau"},
- {HWDEC_VDPAU, "wmv3", "wmv3_vdpau"},
- {HWDEC_VDPAU, "vc1", "vc1_vdpau"},
- {HWDEC_VDPAU, "mpegvideo", "mpegvideo_vdpau"},
- {HWDEC_VDPAU, "mpeg1video", "mpeg1video_vdpau"},
- {HWDEC_VDPAU, "mpeg2video", "mpegvideo_vdpau"},
- {HWDEC_VDPAU, "mpeg2", "mpeg2_vdpau"},
- {HWDEC_VDPAU, "mpeg4", "mpeg4_vdpau"},
+#ifdef CONFIG_VDPAU
+#if HAVE_AV_CODEC_NEW_VDPAU_API
+ {HWDEC_VDPAU, "h264", NULL, &mp_vd_lavc_vdpau},
+ {HWDEC_VDPAU, "wmv3", NULL, &mp_vd_lavc_vdpau},
+ {HWDEC_VDPAU, "vc1", NULL, &mp_vd_lavc_vdpau},
+ {HWDEC_VDPAU, "mpeg1video", NULL, &mp_vd_lavc_vdpau},
+ {HWDEC_VDPAU, "mpeg2video", NULL, &mp_vd_lavc_vdpau},
+ {HWDEC_VDPAU, "mpeg4", NULL, &mp_vd_lavc_vdpau},
+#else
+ {HWDEC_VDPAU, "h264", "h264_vdpau", &mp_vd_lavc_vdpau_old},
+ {HWDEC_VDPAU, "wmv3", "wmv3_vdpau", &mp_vd_lavc_vdpau_old},
+ {HWDEC_VDPAU, "vc1", "vc1_vdpau", &mp_vd_lavc_vdpau_old},
+ {HWDEC_VDPAU, "mpegvideo", "mpegvideo_vdpau", &mp_vd_lavc_vdpau_old},
+ {HWDEC_VDPAU, "mpeg1video", "mpeg1video_vdpau", &mp_vd_lavc_vdpau_old},
+ {HWDEC_VDPAU, "mpeg2video", "mpegvideo_vdpau", &mp_vd_lavc_vdpau_old},
+ {HWDEC_VDPAU, "mpeg2", "mpeg2_vdpau", &mp_vd_lavc_vdpau_old},
+ {HWDEC_VDPAU, "mpeg4", "mpeg4_vdpau", &mp_vd_lavc_vdpau_old},
+#endif
+#endif // CONFIG_VDPAU
{HWDEC_VDA, "h264", "h264_vda"},
@@ -158,17 +171,33 @@ static int init(sh_video_t *sh, const char *decoder)
ctx = sh->context = talloc_zero(NULL, vd_ffmpeg_ctx);
ctx->non_dr1_pool = talloc_steal(ctx, mp_image_pool_new(16));
+ if (bstr_endswith0(bstr0(decoder), "_vdpau")) {
+ mp_tmsg(MSGT_DECVIDEO, MSGL_WARN, "VDPAU decoder '%s' was requested. "
+ "This way of enabling hardware\ndecoding is not supported "
+ "anymore. Use --hwdec=vdpau instead.\nThe --hwdec-codec=... "
+ "option can be used to restrict which codecs are\nenabled, "
+ "otherwise all hardware decoding is tried for all codecs.\n",
+ decoder);
+ uninit(sh);
+ return 0;
+ }
+
struct hwdec *hwdec = find_hwcodec(sh->opts->hwdec_api, decoder);
struct hwdec *use_hwdec = NULL;
if (hwdec && hwdec_codec_allowed(sh, hwdec)) {
- AVCodec *lavc_hwcodec = avcodec_find_decoder_by_name(hwdec->hw_codec);
- if (lavc_hwcodec) {
+ if (hwdec->hw_codec) {
+ AVCodec *lavc_hwcodec = avcodec_find_decoder_by_name(hwdec->hw_codec);
+ if (lavc_hwcodec) {
+ ctx->software_fallback_decoder = talloc_strdup(ctx, decoder);
+ decoder = lavc_hwcodec->name;
+ use_hwdec = hwdec;
+ } else {
+ mp_tmsg(MSGT_DECVIDEO, MSGL_WARN, "Decoder '%s' not found in "
+ "libavcodec, using software decoding.\n", hwdec->hw_codec);
+ }
+ } else {
ctx->software_fallback_decoder = talloc_strdup(ctx, decoder);
- decoder = lavc_hwcodec->name;
use_hwdec = hwdec;
- } else {
- mp_tmsg(MSGT_DECVIDEO, MSGL_WARN, "Decoder '%s' not found in "
- "libavcodec, using software decoding.\n", hwdec->hw_codec);
}
}
@@ -264,6 +293,8 @@ static void init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
if (!lavc_codec)
return;
+ ctx->hwdec_info = sh->hwdec_info;
+
ctx->do_dr1 = ctx->do_hw_dr1 = 0;
ctx->pix_fmt = PIX_FMT_NONE;
ctx->vo_initialized = 0;
@@ -277,26 +308,15 @@ static void init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
avctx->thread_count = lavc_param->threads;
- // Hack to allow explicitly selecting vdpau hw decoders
- if (!hwdec && (lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)) {
- ctx->hwdec = talloc(ctx, struct hwdec);
- *ctx->hwdec = (struct hwdec) {
- .api = HWDEC_VDPAU,
- .codec = sh->gsh->codec,
- .hw_codec = decoder,
- };
- }
-
- if (ctx->hwdec && ctx->hwdec->api == HWDEC_VDPAU) {
- assert(lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU);
+ if (ctx->hwdec && ctx->hwdec->fns) {
ctx->do_hw_dr1 = true;
avctx->thread_count = 1;
- avctx->get_format = get_format_hwdec;
+ if (ctx->hwdec->fns->image_formats)
+ avctx->get_format = get_format_hwdec;
setup_refcounting_hw(avctx);
- if (ctx->hwdec->api == HWDEC_VDPAU) {
- avctx->draw_horiz_band = draw_slice_hwdec;
- avctx->slice_flags =
- SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
+ if (ctx->hwdec->fns->init(ctx) < 0) {
+ uninit_avctx(sh);
+ return;
}
} else {
#if HAVE_AVUTIL_REFCOUNTING
@@ -381,6 +401,9 @@ static void uninit_avctx(sh_video_t *sh)
av_freep(&ctx->avctx);
avcodec_free_frame(&ctx->pic);
+ if (ctx->hwdec && ctx->hwdec->fns)
+ ctx->hwdec->fns->uninit(ctx);
+
#if !HAVE_AVUTIL_REFCOUNTING
mp_buffer_pool_free(&ctx->dr1_buffer_pool);
#endif
@@ -406,11 +429,6 @@ static int init_vo(sh_video_t *sh, AVFrame *frame)
pix_fmt = ctx->avctx->pix_fmt;
#endif
- /* Reconfiguring filter/VO chain may invalidate direct rendering buffers
- * we have allocated for libavcodec (including the VDPAU HW decoding
- * case). Is it guaranteed that the code below only triggers in a situation
- * with no busy direct rendering buffers for reference frames?
- */
if (av_cmp_q(frame->sample_aspect_ratio, ctx->last_sample_aspect_ratio) ||
width != sh->disp_w || height != sh->disp_h ||
pix_fmt != ctx->pix_fmt || !ctx->vo_initialized)
@@ -466,27 +484,19 @@ static enum PixelFormat get_format_hwdec(struct AVCodecContext *avctx,
mp_msg(MSGT_DECVIDEO, MSGL_V, " %s", av_get_pix_fmt_name(fmt[i]));
mp_msg(MSGT_DECVIDEO, MSGL_V, "\n");
- assert(ctx->hwdec);
+ assert(ctx->hwdec && ctx->hwdec->fns);
for (int i = 0; fmt[i] != PIX_FMT_NONE; i++) {
- int imgfmt = pixfmt2imgfmt(fmt[i]);
- if (ctx->hwdec->api == HWDEC_VDPAU && IMGFMT_IS_VDPAU(imgfmt))
- return fmt[i];
+ const int *okfmt = ctx->hwdec->fns->image_formats;
+ for (int n = 0; okfmt && okfmt[n]; n++) {
+ if (imgfmt2pixfmt(okfmt[n]) == fmt[i])
+ return fmt[i];
+ }
}
return PIX_FMT_NONE;
}
-static void draw_slice_hwdec(struct AVCodecContext *s,
- const AVFrame *src, int offset[4],
- int y, int type, int height)
-{
- sh_video_t *sh = s->opaque;
- struct vf_instance *vf = sh->vfilter;
- void *state_ptr = src->data[0];
- vf->control(vf, VFCTRL_HWDEC_DECODER_RENDER, state_ptr);
-}
-
static struct mp_image *get_surface_hwdec(struct sh_video *sh, AVFrame *pic)
{
vd_ffmpeg_ctx *ctx = sh->context;
@@ -506,24 +516,7 @@ static struct mp_image *get_surface_hwdec(struct sh_video *sh, AVFrame *pic)
if (!IMGFMT_IS_HWACCEL(imgfmt))
return NULL;
- // Video with non mod-16 width/height will have allocation sizes that are
- // rounded up. This conflicts with our video size change detection and
- // leads to an endless loop. On the other hand, vdpau seems to round up
- // frame allocations internally. So use the original video resolution
- // instead.
- AVFrame pic_resized = *pic;
- pic_resized.width = ctx->avctx->width;
- pic_resized.height = ctx->avctx->height;
-
- if (init_vo(sh, &pic_resized) < 0)
- return NULL;
-
- assert(IMGFMT_IS_HWACCEL(ctx->best_csp));
-
- struct mp_image *mpi = NULL;
-
- struct vf_instance *vf = sh->vfilter;
- vf->control(vf, VFCTRL_HWDEC_ALLOC_SURFACE, &mpi);
+ struct mp_image *mpi = ctx->hwdec->fns->allocate_image(ctx, pic);
if (mpi) {
for (int i = 0; i < 4; i++)
@@ -698,6 +691,9 @@ static int decode(struct sh_video *sh, struct demux_packet *packet,
struct mp_image *mpi = image_from_decoder(sh);
assert(mpi->planes[0]);
+ if (ctx->hwdec && ctx->hwdec->fns && ctx->hwdec->fns->fix_image)
+ ctx->hwdec->fns->fix_image(ctx, mpi);
+
mpi->colorspace = ctx->image_params.colorspace;
mpi->levels = ctx->image_params.colorlevels;
mpi->chroma_location = ctx->image_params.chroma_location;
diff --git a/video/decode/vdpau.c b/video/decode/vdpau.c
new file mode 100644
index 0000000000..512f9170a3
--- /dev/null
+++ b/video/decode/vdpau.c
@@ -0,0 +1,228 @@
+/*
+ * This file is part of mpv.
+ *
+ * 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 <libavcodec/vdpau.h>
+#include <libavutil/common.h>
+
+#include "lavc.h"
+#include "core/mp_common.h"
+#include "video/fmt-conversion.h"
+#include "video/vdpau.h"
+#include "video/decode/dec_video.h"
+
+struct priv {
+ struct mp_vdpau_ctx *mpvdp;
+ struct vdp_functions *vdp;
+ VdpDevice vdp_device;
+ uint64_t preemption_counter;
+
+ AVVDPAUContext context;
+
+ int vid_width;
+ int vid_height;
+};
+
+struct profile_entry {
+ enum AVCodecID av_codec;
+ int ff_profile;
+ VdpDecoderProfile vdp_profile;
+ int maxrefs;
+};
+
+#define PE(av_codec_id, ff_profile, vdp_dcoder_profile, maxrefs) \
+ {AV_CODEC_ID_ ## av_codec_id, \
+ FF_PROFILE_ ## ff_profile, \
+ VDP_DECODER_PROFILE_ ## vdp_dcoder_profile, \
+ maxrefs}
+
+static const struct profile_entry profiles[] = {
+ PE(MPEG1VIDEO, UNKNOWN, MPEG1, 2),
+ PE(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2_SIMPLE, 2),
+ PE(MPEG2VIDEO, UNKNOWN, MPEG2_MAIN, 2),
+ PE(H264, H264_BASELINE, H264_BASELINE, 16),
+ PE(H264, H264_CONSTRAINED_BASELINE, H264_BASELINE, 16),
+ PE(H264, H264_MAIN, H264_MAIN, 16),
+ PE(H264, UNKNOWN, H264_HIGH, 16),
+ PE(WMV3, VC1_SIMPLE, VC1_SIMPLE, 2),
+ PE(WMV3, VC1_MAIN, VC1_MAIN, 2),
+ PE(WMV3, UNKNOWN, VC1_ADVANCED, 2),
+ PE(VC1, VC1_SIMPLE, VC1_SIMPLE, 2),
+ PE(VC1, VC1_MAIN, VC1_MAIN, 2),
+ PE(VC1, UNKNOWN, VC1_ADVANCED, 2),
+ PE(MPEG4, MPEG4_SIMPLE, MPEG4_PART2_SP, 2),
+ PE(MPEG4, UNKNOWN, MPEG4_PART2_ASP,2),
+};
+
+// libavcodec absolutely wants a non-NULL render callback
+static VdpStatus dummy_render(
+ VdpDecoder decoder,
+ VdpVideoSurface target,
+ VdpPictureInfo const * picture_info,
+ uint32_t bitstream_buffer_count,
+ VdpBitstreamBuffer const * bitstream_buffers)
+{
+ return VDP_STATUS_DISPLAY_PREEMPTED;
+}
+
+static void mark_uninitialized(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ p->vdp_device = VDP_INVALID_HANDLE;
+ p->context.decoder = VDP_INVALID_HANDLE;
+ p->context.render = dummy_render;
+}
+
+static int handle_preemption(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ if (!mp_vdpau_status_ok(p->mpvdp))
+ return -1;
+
+ // Mark objects as destroyed if preemption+reinit occured
+ if (p->preemption_counter < p->mpvdp->preemption_counter) {
+ p->preemption_counter = p->mpvdp->preemption_counter;
+ mark_uninitialized(ctx);
+ }
+
+ p->vdp_device = p->mpvdp->vdp_device;
+ p->vdp = p->mpvdp->vdp;
+
+ return 0;
+}
+
+static bool create_vdp_decoder(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+ struct vdp_functions *vdp = p->mpvdp->vdp;
+ VdpStatus vdp_st;
+
+ if (handle_preemption(ctx) < 0)
+ return false;
+
+ if (p->context.decoder != VDP_INVALID_HANDLE)
+ vdp->decoder_destroy(p->context.decoder);
+
+ const struct profile_entry *pe = NULL;
+ for (int n = 0; n < MP_ARRAY_SIZE(profiles); n++) {
+ if (profiles[n].av_codec == ctx->avctx->codec_id &&
+ (profiles[n].ff_profile == ctx->avctx->profile ||
+ profiles[n].ff_profile == FF_PROFILE_UNKNOWN))
+ {
+ pe = &profiles[n];
+ break;
+ }
+ }
+
+ if (!pe) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unknown codec!\n");
+ goto fail;
+ }
+
+ vdp_st = vdp->decoder_create(p->vdp_device, pe->vdp_profile,
+ p->vid_width, p->vid_height, pe->maxrefs,
+ &p->context.decoder);
+ CHECK_ST_WARNING("Failed creating VDPAU decoder");
+ p->context.render = p->vdp->decoder_render;
+ if (vdp_st != VDP_STATUS_OK)
+ goto fail;
+ return true;
+
+fail:
+ p->context.decoder = VDP_INVALID_HANDLE;
+ p->context.render = dummy_render;
+ return false;
+}
+
+static struct mp_image *allocate_image(struct lavc_ctx *ctx, AVFrame *frame)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ if (frame->format != AV_PIX_FMT_VDPAU)
+ return NULL;
+
+ // frame->width/height lie. Using them breaks with non-mod 16 video.
+ int w = ctx->avctx->width;
+ int h = ctx->avctx->height;
+
+ handle_preemption(ctx);
+
+ if (w != p->vid_width || h != p->vid_height ||
+ p->context.decoder == VDP_INVALID_HANDLE)
+ {
+ p->vid_width = w;
+ p->vid_height = h;
+ if (!create_vdp_decoder(ctx))
+ return NULL;
+ }
+
+ VdpChromaType chroma;
+ mp_vdpau_get_format(IMGFMT_VDPAU, &chroma, NULL);
+
+ return mp_vdpau_get_video_surface(p->mpvdp, IMGFMT_VDPAU, chroma, w, h);
+}
+
+static void uninit(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ if (!p)
+ return;
+
+ if (p->context.decoder != VDP_INVALID_HANDLE)
+ p->vdp->decoder_destroy(p->context.decoder);
+
+ // Free bitstream buffers allocated by libavcodec
+ av_freep(&p->context.bitstream_buffers);
+
+ talloc_free(p);
+
+ ctx->hwdec_priv = NULL;
+}
+
+static int init(struct lavc_ctx *ctx)
+{
+ if (!ctx->hwdec_info || !ctx->hwdec_info->vdpau_ctx)
+ return -1;
+
+ struct priv *p = talloc_ptrtype(NULL, p);
+ *p = (struct priv) {
+ .mpvdp = ctx->hwdec_info->vdpau_ctx,
+ };
+ ctx->hwdec_priv = p;
+
+ p->preemption_counter = p->mpvdp->preemption_counter;
+ mark_uninitialized(ctx);
+
+ if (handle_preemption(ctx) < 0)
+ return -1;
+
+ ctx->avctx->hwaccel_context = &p->context;
+
+ return 0;
+}
+
+const struct vd_lavc_hwdec_functions mp_vd_lavc_vdpau = {
+ .image_formats = (const int[]) {IMGFMT_VDPAU, 0},
+ .init = init,
+ .uninit = uninit,
+ .allocate_image = allocate_image,
+};
diff --git a/video/decode/vdpau_old.c b/video/decode/vdpau_old.c
new file mode 100644
index 0000000000..e9c88b69ea
--- /dev/null
+++ b/video/decode/vdpau_old.c
@@ -0,0 +1,267 @@
+/*
+ * VDPAU video output driver
+ *
+ * Copyright (C) 2008 NVIDIA
+ * Copyright (C) 2009 Uoti Urpala
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stddef.h>
+#include <assert.h>
+
+#include <libavcodec/vdpau.h>
+#include <libavutil/common.h>
+
+#include "lavc.h"
+#include "video/fmt-conversion.h"
+#include "video/vdpau.h"
+#include "video/decode/dec_video.h"
+
+struct priv {
+ struct mp_vdpau_ctx *mpvdp;
+ struct vdp_functions *vdp;
+ VdpDevice vdp_device;
+ uint64_t preemption_counter;
+
+ int image_format;
+ int vid_width;
+ int vid_height;
+
+ VdpDecoder decoder;
+ int decoder_max_refs;
+};
+
+static void mark_uninitialized(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ p->vdp_device = VDP_INVALID_HANDLE;
+ p->decoder = VDP_INVALID_HANDLE;
+}
+
+static int handle_preemption(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ if (!mp_vdpau_status_ok(p->mpvdp))
+ return -1;
+
+ // Mark objects as destroyed if preemption+reinit occured
+ if (p->preemption_counter < p->mpvdp->preemption_counter) {
+ p->preemption_counter = p->mpvdp->preemption_counter;
+ mark_uninitialized(ctx);
+ }
+
+ p->vdp_device = p->mpvdp->vdp_device;
+ p->vdp = p->mpvdp->vdp;
+
+ return 0;
+}
+
+static bool create_vdp_decoder(struct lavc_ctx *ctx, int max_refs)
+{
+ struct priv *p = ctx->hwdec_priv;
+ struct vdp_functions *vdp = p->mpvdp->vdp;
+ VdpStatus vdp_st;
+ VdpDecoderProfile vdp_decoder_profile;
+
+ if (handle_preemption(ctx) < 0)
+ return false;
+
+ if (p->decoder != VDP_INVALID_HANDLE)
+ vdp->decoder_destroy(p->decoder);
+
+ switch (p->image_format) {
+ case IMGFMT_VDPAU_MPEG1:
+ vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
+ break;
+ case IMGFMT_VDPAU_MPEG2:
+ vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
+ break;
+ case IMGFMT_VDPAU_H264:
+ vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder "
+ "for %d reference frames.\n", max_refs);
+ break;
+ case IMGFMT_VDPAU_WMV3:
+ vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
+ break;
+ case IMGFMT_VDPAU_VC1:
+ vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
+ break;
+ case IMGFMT_VDPAU_MPEG4:
+ vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
+ break;
+ default:
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unknown image format!\n");
+ goto fail;
+ }
+ vdp_st = vdp->decoder_create(p->vdp_device, vdp_decoder_profile,
+ p->vid_width, p->vid_height, max_refs,
+ &p->decoder);
+ CHECK_ST_WARNING("Failed creating VDPAU decoder");
+ if (vdp_st != VDP_STATUS_OK)
+ goto fail;
+ p->decoder_max_refs = max_refs;
+ return true;
+
+fail:
+ p->decoder = VDP_INVALID_HANDLE;
+ p->decoder_max_refs = 0;
+ return false;
+}
+
+static void draw_slice_hwdec(struct AVCodecContext *s,
+ const AVFrame *src, int offset[4],
+ int y, int type, int height)
+{
+ sh_video_t *sh = s->opaque;
+ struct lavc_ctx *ctx = sh->context;
+ struct priv *p = ctx->hwdec_priv;
+ struct vdp_functions *vdp = p->vdp;
+ VdpStatus vdp_st;
+
+ if (handle_preemption(ctx) < 0)
+ return;
+
+ struct vdpau_render_state *rndr = (void *)src->data[0];
+
+ int max_refs = p->image_format == IMGFMT_VDPAU_H264 ?
+ rndr->info.h264.num_ref_frames : 2;
+ if ((p->decoder == VDP_INVALID_HANDLE || p->decoder_max_refs < max_refs)
+ && !create_vdp_decoder(ctx, max_refs))
+ return;
+
+ vdp_st = vdp->decoder_render(p->decoder, rndr->surface,
+ (void *)&rndr->info,
+ rndr->bitstream_buffers_used,
+ rndr->bitstream_buffers);
+ CHECK_ST_WARNING("Failed VDPAU decoder rendering");
+}
+
+static void release_surface(void *ptr)
+{
+ struct vdpau_render_state *state = ptr;
+ // Free bitstream buffers allocated by libavcodec
+ av_freep(&state->bitstream_buffers);
+ talloc_free(state);
+}
+
+static struct mp_image *allocate_image(struct lavc_ctx *ctx, AVFrame *frame)
+{
+ struct priv *p = ctx->hwdec_priv;
+ int imgfmt = pixfmt2imgfmt(frame->format);
+
+ if (!IMGFMT_IS_VDPAU(imgfmt))
+ return NULL;
+
+ // frame->width/height lie. Using them breaks with non-mod 16 video.
+ int w = ctx->avctx->width;
+ int h = ctx->avctx->height;
+
+ if (w != p->vid_width || h != p->vid_height || imgfmt != p->image_format) {
+ p->vid_width = w;
+ p->vid_height = h;
+ p->image_format = imgfmt;
+ if (!create_vdp_decoder(ctx, 2))
+ return NULL;
+ }
+
+ VdpChromaType chroma;
+ mp_vdpau_get_format(p->image_format, &chroma, NULL);
+
+ struct mp_image *img =
+ mp_vdpau_get_video_surface(p->mpvdp, imgfmt, chroma, w, h);
+
+ if (!img)
+ return NULL;
+
+ // Create chained reference for vdpau_render_state. This will track the
+ // lifetime of the actual reference too.
+ // This is quite roundabout, but at least it allows us to share the
+ // surface allocator in vo_vdpau.c with the new vdpau code.
+
+ struct vdpau_render_state *state = talloc_ptrtype(NULL, state);
+ memset(state, 0, sizeof(*state));
+ state->surface = (VdpVideoSurface)(intptr_t)img->planes[3];
+
+ talloc_steal(state, img);
+
+ struct mp_image *new = mp_image_new_custom_ref(img, state, release_surface);
+ new->planes[0] = (void *)state;
+ return new;
+}
+
+static void uninit(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ if (!p)
+ return;
+
+ if (p->decoder != VDP_INVALID_HANDLE)
+ p->vdp->decoder_destroy(p->decoder);
+
+ talloc_free(p);
+ ctx->hwdec_priv = NULL;
+}
+
+static int init(struct lavc_ctx *ctx)
+{
+ if (!ctx->hwdec_info || !ctx->hwdec_info->vdpau_ctx)
+ return -1;
+
+ struct priv *p = talloc_ptrtype(NULL, p);
+ *p = (struct priv) {
+ .mpvdp = ctx->hwdec_info->vdpau_ctx,
+ };
+ ctx->hwdec_priv = p;
+
+ p->preemption_counter = p->mpvdp->preemption_counter;
+ mark_uninitialized(ctx);
+
+ if (handle_preemption(ctx) < 0)
+ return -1;
+
+ AVCodecContext *avctx = ctx->avctx;
+
+ avctx->draw_horiz_band = draw_slice_hwdec;
+ avctx->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
+
+ return 0;
+}
+
+static void fix_image(struct lavc_ctx *ctx, struct mp_image *img)
+{
+ // Make it follow the convention of the "new" vdpau decoder
+ struct vdpau_render_state *rndr = (void *)img->planes[0];
+ img->planes[0] = (void *)"dummy"; // must be non-NULL, otherwise arbitrary
+ img->planes[3] = (void *)(intptr_t)rndr->surface;
+}
+
+const struct vd_lavc_hwdec_functions mp_vd_lavc_vdpau_old = {
+ .image_formats = (const int[]) {
+ IMGFMT_VDPAU_MPEG1, IMGFMT_VDPAU_MPEG2, IMGFMT_VDPAU_H264,
+ IMGFMT_VDPAU_WMV3, IMGFMT_VDPAU_VC1, IMGFMT_VDPAU_MPEG4,
+ 0
+ },
+ .init = init,
+ .uninit = uninit,
+ .allocate_image = allocate_image,
+ .fix_image = fix_image,
+};
diff --git a/video/filter/vf.h b/video/filter/vf.h
index d115890f64..c792049b3b 100644
--- a/video/filter/vf.h
+++ b/video/filter/vf.h
@@ -99,8 +99,6 @@ typedef struct vf_seteq {
#define VFCTRL_SET_PP_LEVEL 5 // set postprocessing level
#define VFCTRL_SET_EQUALIZER 6 // set color options (brightness,contrast etc)
#define VFCTRL_GET_EQUALIZER 8 // get color options (brightness,contrast etc)
-#define VFCTRL_HWDEC_DECODER_RENDER 9 // vdpau hw decoding
-#define VFCTRL_HWDEC_ALLOC_SURFACE 10 // vdpau hw decoding
#define VFCTRL_SCREENSHOT 14 // Take screenshot, arg is voctrl_screenshot_args
#define VFCTRL_INIT_OSD 15 // Filter OSD renderer present?
#define VFCTRL_SET_DEINTERLACE 18 // Set deinterlacing status
diff --git a/video/filter/vf_vo.c b/video/filter/vf_vo.c
index 60113192b7..9edb393e23 100644
--- a/video/filter/vf_vo.c
+++ b/video/filter/vf_vo.c
@@ -87,10 +87,6 @@ static int control(struct vf_instance *vf, int request, void *data)
};
return vo_control(video_out, VOCTRL_GET_EQUALIZER, &param) == VO_TRUE;
}
- case VFCTRL_HWDEC_DECODER_RENDER:
- return vo_control(video_out, VOCTRL_HWDEC_DECODER_RENDER, data);
- case VFCTRL_HWDEC_ALLOC_SURFACE:
- return vo_control(video_out, VOCTRL_HWDEC_ALLOC_SURFACE, data);
}
return CONTROL_UNKNOWN;
}
diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c
index 153b1badf3..500b4b1609 100644
--- a/video/fmt-conversion.c
+++ b/video/fmt-conversion.c
@@ -171,12 +171,18 @@ static const struct {
{IMGFMT_BGRA64_LE, PIX_FMT_BGRA64LE},
#endif
+#if HAVE_AV_CODEC_NEW_VDPAU_API
+ {IMGFMT_VDPAU, AV_PIX_FMT_VDPAU},
+#else
{IMGFMT_VDPAU_MPEG1, PIX_FMT_VDPAU_MPEG1},
{IMGFMT_VDPAU_MPEG2, PIX_FMT_VDPAU_MPEG2},
{IMGFMT_VDPAU_H264, PIX_FMT_VDPAU_H264},
{IMGFMT_VDPAU_WMV3, PIX_FMT_VDPAU_WMV3},
{IMGFMT_VDPAU_VC1, PIX_FMT_VDPAU_VC1},
{IMGFMT_VDPAU_MPEG4, PIX_FMT_VDPAU_MPEG4},
+ // map to an arbitrary but existing vdpau format
+ {IMGFMT_VDPAU, PIX_FMT_VDPAU_H264},
+#endif
{0, PIX_FMT_NONE}
};
diff --git a/video/img_format.c b/video/img_format.c
index c0bbce90ee..9422fbdd27 100644
--- a/video/img_format.c
+++ b/video/img_format.c
@@ -118,6 +118,7 @@ struct mp_imgfmt_entry mp_imgfmt_list[] = {
FMT("vdpau_wmv3", IMGFMT_VDPAU_WMV3)
FMT("vdpau_vc1", IMGFMT_VDPAU_VC1)
FMT("vdpau_mpeg4", IMGFMT_VDPAU_MPEG4)
+ FMT("vdpau", IMGFMT_VDPAU)
{0}
};
diff --git a/video/img_format.h b/video/img_format.h
index aac828d580..2438c231b8 100644
--- a/video/img_format.h
+++ b/video/img_format.h
@@ -242,14 +242,15 @@ enum mp_imgfmt {
// Hardware accelerated formats. Plane data points to special data
// structures, instead of pixel data.
- IMGFMT_VDPAU_MPEG1,
+ IMGFMT_VDPAU, // new decoder API
+ IMGFMT_VDPAU_MPEG1, // old API
IMGFMT_VDPAU_MPEG2,
IMGFMT_VDPAU_H264,
IMGFMT_VDPAU_WMV3,
IMGFMT_VDPAU_VC1,
IMGFMT_VDPAU_MPEG4,
- IMGFMT_VDPAU_FIRST = IMGFMT_VDPAU_MPEG1,
+ IMGFMT_VDPAU_FIRST = IMGFMT_VDPAU,
IMGFMT_VDPAU_LAST = IMGFMT_VDPAU_MPEG4,
IMGFMT_END,
diff --git a/video/out/vo.h b/video/out/vo.h
index ae84f9d0c9..3abb8fca58 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -51,8 +51,7 @@ enum mp_voctrl {
VOCTRL_GET_EQUALIZER, // struct voctrl_get_equalizer_args*
/* for vdpau hardware decoding */
- VOCTRL_HWDEC_DECODER_RENDER, // pointer to hw state
- VOCTRL_HWDEC_ALLOC_SURFACE, // struct mp_image**
+ VOCTRL_GET_HWDEC_INFO, // struct mp_hwdec_info*
VOCTRL_NEWFRAME,
VOCTRL_SKIPFRAME,
diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c
index 6f1483cdd9..414071b5a0 100644
--- a/video/out/vo_vdpau.c
+++ b/video/out/vo_vdpau.c
@@ -22,10 +22,7 @@
*/
/*
- * Actual decoding and presentation are implemented here.
- * All necessary frame information is collected through
- * the "vdpau_render_state" structure after parsing all headers
- * etc. in libavcodec for different codecs.
+ * Actual decoding is done in video/decode/vdpau.c
*/
#include <stdio.h>
@@ -36,9 +33,10 @@
#include <assert.h>
#include <libavutil/common.h>
-#include <libavcodec/vdpau.h>
#include "config.h"
+#include "video/vdpau.h"
+#include "video/decode/dec_video.h"
#include "core/mp_msg.h"
#include "core/options.h"
#include "talloc.h"
@@ -56,21 +54,6 @@
? ((x)+(a)+(m) < (m) ? (x)+(a)+(m) : (x)+(a)) \
: ((x)+(a) < (m) ? (x)+(a) : (x)+(a)-(m)))
-#define CHECK_ST_ERROR(message) \
- do { \
- if (vdp_st != VDP_STATUS_OK) { \
- mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
- message, vdp->get_error_string(vdp_st)); \
- return -1; \
- } \
- } while (0)
-
-#define CHECK_ST_WARNING(message) \
- do { \
- if (vdp_st != VDP_STATUS_OK) \
- mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \
- message, vdp->get_error_string(vdp_st)); \
- } while (0)
/* number of video and output surfaces */
#define MAX_OUTPUT_SURFACES 15
@@ -84,21 +67,15 @@
* Global variable declaration - VDPAU specific
*/
-struct vdp_functions {
-#define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
-#include "vdpau_template.c"
-#undef VDP_FUNCTION
-};
-
struct vdpctx {
- struct vdp_functions *vdp;
-
+ struct mp_vdpau_ctx mpvdp;
+ struct vdp_functions *vdp;
VdpDevice vdp_device;
+
bool is_preempted;
bool preemption_acked;
bool preemption_user_notified;
double last_preemption_retry_fail;
- VdpGetProcAddress *vdp_get_proc_address;
VdpPresentationQueueTarget flip_target;
VdpPresentationQueue flip_queue;
@@ -131,15 +108,18 @@ struct vdpctx {
int top_field_first;
bool flip;
- VdpDecoder decoder;
- int decoder_max_refs;
-
VdpRect src_rect_vid;
VdpRect out_rect_vid;
struct mp_osd_res osd_rect;
- struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES];
- bool surface_in_use[MAX_VIDEO_SURFACES];
+ // Surface pool
+ struct surface_entry {
+ VdpVideoSurface surface;
+ int fmt, w, h;
+ VdpChromaType chroma;
+ bool in_use;
+ } video_surfaces[MAX_VIDEO_SURFACES];
+
int surface_num; // indexes output_surfaces
int query_surface_num;
VdpTime recent_vsync_time;
@@ -334,7 +314,7 @@ static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface,
for (int i = NUM_BUFFERED_VIDEO - 1; i > 0; i--)
bv[i] = bv[i - 1];
bv[0] = (struct buffered_video_surface){
- .mpi = reserved_mpi ? mp_image_new_ref(reserved_mpi) : NULL,
+ .mpi = reserved_mpi,
.surface = surface,
.pts = pts,
};
@@ -419,21 +399,19 @@ static void preemption_callback(VdpDevice device, void *context)
{
struct vdpctx *vc = context;
vc->is_preempted = true;
+ vc->mpvdp.is_preempted = true;
vc->preemption_acked = false;
}
-/* Initialize vdp_get_proc_address, called from preinit() */
static int win_x11_init_vdpau_procs(struct vo *vo)
{
struct vo_x11_state *x11 = vo->x11;
struct vdpctx *vc = vo->priv;
- if (vc->vdp) // reinitialization after preemption
- memset(vc->vdp, 0, sizeof(*vc->vdp));
- else
- vc->vdp = talloc_zero(vc, struct vdp_functions);
struct vdp_functions *vdp = vc->vdp;
VdpStatus vdp_st;
+ *vdp = (struct vdp_functions){0};
+
struct vdp_function {
const int id;
int offset;
@@ -448,8 +426,10 @@ static int win_x11_init_vdpau_procs(struct vo *vo)
{0, -1}
};
+ VdpGetProcAddress *get_proc_address;
vdp_st = vdp_device_create_x11(x11->display, x11->screen, &vc->vdp_device,
- &vc->vdp_get_proc_address);
+ &get_proc_address);
+ vc->mpvdp.vdp_device = vc->vdp_device;
if (vdp_st != VDP_STATUS_OK) {
if (vc->is_preempted)
mp_msg(MSGT_VO, MSGL_DBG2, "[vdpau] Error calling "
@@ -462,7 +442,7 @@ static int win_x11_init_vdpau_procs(struct vo *vo)
vdp->get_error_string = NULL;
for (dsc = vdp_func; dsc->offset >= 0; dsc++) {
- vdp_st = vc->vdp_get_proc_address(vc->vdp_device, dsc->id,
+ vdp_st = get_proc_address(vc->vdp_device, dsc->id,
(void **)((char *)vdp + dsc->offset));
if (vdp_st != VDP_STATUS_OK) {
mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling "
@@ -671,24 +651,10 @@ static void free_video_specific(struct vo *vo)
{
struct vdpctx *vc = vo->priv;
struct vdp_functions *vdp = vc->vdp;
- int i;
VdpStatus vdp_st;
- if (vc->decoder != VDP_INVALID_HANDLE)
- vdp->decoder_destroy(vc->decoder);
- vc->decoder = VDP_INVALID_HANDLE;
- vc->decoder_max_refs = -1;
-
forget_frames(vo);
- for (i = 0; i < MAX_VIDEO_SURFACES; i++) {
- if (vc->surface_render[i].surface != VDP_INVALID_HANDLE) {
- vdp_st = vdp->video_surface_destroy(vc->surface_render[i].surface);
- CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
- }
- vc->surface_render[i].surface = VDP_INVALID_HANDLE;
- }
-
if (vc->video_mixer != VDP_INVALID_HANDLE) {
vdp_st = vdp->video_mixer_destroy(vc->video_mixer);
CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy");
@@ -702,73 +668,13 @@ static void free_video_specific(struct vo *vo)
vc->screenshot_surface = VDP_INVALID_HANDLE;
}
-static int create_vdp_decoder(struct vo *vo, int max_refs)
-{
- struct vdpctx *vc = vo->priv;
- struct vdp_functions *vdp = vc->vdp;
- VdpStatus vdp_st;
- VdpDecoderProfile vdp_decoder_profile;
- if (vc->decoder != VDP_INVALID_HANDLE)
- vdp->decoder_destroy(vc->decoder);
- switch (vc->image_format) {
- case IMGFMT_VDPAU_MPEG1:
- vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
- break;
- case IMGFMT_VDPAU_MPEG2:
- vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
- break;
- case IMGFMT_VDPAU_H264:
- vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
- mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder "
- "for %d reference frames.\n", max_refs);
- break;
- case IMGFMT_VDPAU_WMV3:
- vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
- break;
- case IMGFMT_VDPAU_VC1:
- vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
- break;
- case IMGFMT_VDPAU_MPEG4:
- vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
- break;
- default:
- mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unknown image format!\n");
- goto fail;
- }
- vdp_st = vdp->decoder_create(vc->vdp_device, vdp_decoder_profile,
- vc->vid_width, vc->vid_height, max_refs,
- &vc->decoder);
- CHECK_ST_WARNING("Failed creating VDPAU decoder");
- if (vdp_st != VDP_STATUS_OK) {
- fail:
- vc->decoder = VDP_INVALID_HANDLE;
- vc->decoder_max_refs = 0;
- return 0;
- }
- vc->decoder_max_refs = max_refs;
- return 1;
-}
-
static int initialize_vdpau_objects(struct vo *vo)
{
struct vdpctx *vc = vo->priv;
- vc->vdp_chroma_type = VDP_CHROMA_TYPE_420;
- switch (vc->image_format) {
- case IMGFMT_420P:
- vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YV12;
- break;
- case IMGFMT_NV12:
- vc->vdp_pixel_format = VDP_YCBCR_FORMAT_NV12;
- break;
- case IMGFMT_YUYV:
- vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YUYV;
- vc->vdp_chroma_type = VDP_CHROMA_TYPE_422;
- break;
- case IMGFMT_UYVY:
- vc->vdp_pixel_format = VDP_YCBCR_FORMAT_UYVY;
- vc->vdp_chroma_type = VDP_CHROMA_TYPE_422;
- }
+ mp_vdpau_get_format(vc->image_format, &vc->vdp_chroma_type,
+ &vc->vdp_pixel_format);
+
if (win_x11_init_vdpau_flip_queue(vo) < 0)
return -1;
@@ -784,9 +690,8 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
{
struct vdpctx *vc = vo->priv;
- vc->decoder = VDP_INVALID_HANDLE;
for (int i = 0; i < MAX_VIDEO_SURFACES; i++)
- vc->surface_render[i].surface = VDP_INVALID_HANDLE;
+ vc->video_surfaces[i].surface = VDP_INVALID_HANDLE;
forget_frames(vo);
vc->video_mixer = VDP_INVALID_HANDLE;
vc->flip_queue = VDP_INVALID_HANDLE;
@@ -795,6 +700,7 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
vc->output_surfaces[i] = VDP_INVALID_HANDLE;
vc->screenshot_surface = VDP_INVALID_HANDLE;
vc->vdp_device = VDP_INVALID_HANDLE;
+ vc->mpvdp.vdp_device = vc->vdp_device;
for (int i = 0; i < MAX_OSD_PARTS; i++) {
struct osd_bitmap_surface *sfc = &vc->osd_surfaces[i];
talloc_free(sfc->packer);
@@ -831,11 +737,24 @@ static int handle_preemption(struct vo *vo)
}
vc->last_preemption_retry_fail = 0;
vc->is_preempted = false;
+ vc->mpvdp.is_preempted = false;
+ vc->mpvdp.preemption_counter++;
vc->preemption_user_notified = false;
mp_tmsg(MSGT_VO, MSGL_INFO, "[vdpau] Recovered from display preemption.\n");
return 1;
}
+static bool status_ok(struct vo *vo)
+{
+ return vo->config_ok && handle_preemption(vo) >= 0;
+}
+
+static bool ctx_status_ok(struct mp_vdpau_ctx *ctx)
+{
+ struct vo *vo = ctx->priv;
+ return handle_preemption(vo) >= 0;
+}
+
/*
* connect to X server, create and map window, initialize all
* VDPAU objects, create different surfaces etc.
@@ -855,8 +774,6 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
vc->vid_height = height;
free_video_specific(vo);
- if (IMGFMT_IS_VDPAU(vc->image_format) && !create_vdp_decoder(vo, 2))
- return -1;
vo_x11_config_vo_window(vo, NULL, vo->dx, vo->dy, d_width, d_height,
flags, "vdpau");
@@ -1191,51 +1108,82 @@ static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration)
vc->surface_num = WRAP_ADD(vc->surface_num, 1, vc->num_output_surfaces);
}
-static int decoder_render(struct vo *vo, void *state_ptr)
+static void release_decoder_surface(void *ptr)
{
- struct vdpctx *vc = vo->priv;
- struct vdp_functions *vdp = vc->vdp;
- VdpStatus vdp_st;
- struct vdpau_render_state *rndr = (struct vdpau_render_state *)state_ptr;
-
- if (handle_preemption(vo) < 0)
- return VO_TRUE;
-
- int max_refs = vc->image_format == IMGFMT_VDPAU_H264 ?
- rndr->info.h264.num_ref_frames : 2;
- if (!IMGFMT_IS_VDPAU(vc->image_format))
- return VO_FALSE;
- if ((vc->decoder == VDP_INVALID_HANDLE || vc->decoder_max_refs < max_refs)
- && !create_vdp_decoder(vo, max_refs))
- return VO_FALSE;
-
- vdp_st = vdp->decoder_render(vc->decoder, rndr->surface,
- (void *)&rndr->info,
- rndr->bitstream_buffers_used,
- rndr->bitstream_buffers);
- CHECK_ST_WARNING("Failed VDPAU decoder rendering");
- return VO_TRUE;
+ bool *in_use_ptr = ptr;
+ *in_use_ptr = false;
}
+static struct mp_image *create_ref(struct surface_entry *e)
+{
+ assert(!e->in_use);
+ e->in_use = true;
+ struct mp_image *res =
+ mp_image_new_custom_ref(&(struct mp_image){0}, &e->in_use,
+ release_decoder_surface);
+ mp_image_setfmt(res, e->fmt);
+ mp_image_set_size(res, e->w, e->h);
+ res->planes[0] = (void *)"dummy"; // must be non-NULL, otherwise arbitrary
+ res->planes[3] = (void *)(intptr_t)e->surface;
+ return res;
+}
-static struct vdpau_render_state *get_surface(struct vo *vo, int number)
+static struct mp_image *get_video_surface(struct mp_vdpau_ctx *ctx, int fmt,
+ VdpChromaType chroma, int w, int h)
{
+ struct vo *vo = ctx->priv;
struct vdpctx *vc = vo->priv;
struct vdp_functions *vdp = vc->vdp;
+ VdpStatus vdp_st;
- if (number >= MAX_VIDEO_SURFACES)
- return NULL;
- if (vc->surface_render[number].surface == VDP_INVALID_HANDLE
- && !vc->is_preempted) {
- VdpStatus vdp_st;
- vdp_st = vdp->video_surface_create(vc->vdp_device, vc->vdp_chroma_type,
- vc->vid_width, vc->vid_height,
- &vc->surface_render[number].surface);
- CHECK_ST_WARNING("Error when calling vdp_video_surface_create");
+ assert(IMGFMT_IS_VDPAU(fmt));
+
+ // Destroy all unused surfaces that don't have matching parameters
+ for (int n = 0; n < MAX_VIDEO_SURFACES; n++) {
+ struct surface_entry *e = &vc->video_surfaces[n];
+ if (!e->in_use && e->surface != VDP_INVALID_HANDLE) {
+ if (e->fmt != fmt || e->chroma != chroma || e->w != w || e->h != h) {
+ vdp_st = vdp->video_surface_destroy(e->surface);
+ CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
+ e->surface = VDP_INVALID_HANDLE;
+ }
+ }
}
- mp_msg(MSGT_VO, MSGL_DBG3, "vdpau vid create: %u\n",
- vc->surface_render[number].surface);
- return &vc->surface_render[number];
+
+ // Try to find an existing unused surface
+ for (int n = 0; n < MAX_VIDEO_SURFACES; n++) {
+ struct surface_entry *e = &vc->video_surfaces[n];
+ if (!e->in_use && e->surface != VDP_INVALID_HANDLE) {
+ assert(e->w == w && e->h == h);
+ assert(e->fmt == fmt && e->chroma == chroma);
+ return create_ref(e);
+ }
+ }
+
+ // Allocate new surface
+ for (int n = 0; n < MAX_VIDEO_SURFACES; n++) {
+ struct surface_entry *e = &vc->video_surfaces[n];
+ if (!e->in_use) {
+ assert(e->surface == VDP_INVALID_HANDLE);
+ e->fmt = fmt;
+ e->chroma = chroma;
+ e->w = w;
+ e->h = h;
+ if (vc->is_preempted) {
+ mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] Preempted, no surface.\n");
+ } else {
+ vdp_st = vdp->video_surface_create(vc->vdp_device, chroma,
+ w, h, &e->surface);
+ CHECK_ST_WARNING("Error when calling vdp_video_surface_create");
+ }
+ return create_ref(e);
+ }
+ }
+
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] no surfaces available in "
+ "get_video_surface\n");
+ // TODO: this probably breaks things forever, provide a dummy buffer?
+ return NULL;
}
static void draw_image(struct vo *vo, mp_image_t *mpi)
@@ -1243,13 +1191,17 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
struct vdpctx *vc = vo->priv;
struct vdp_functions *vdp = vc->vdp;
struct mp_image *reserved_mpi = NULL;
- struct vdpau_render_state *rndr;
+ VdpVideoSurface surface = VDP_INVALID_HANDLE;
if (IMGFMT_IS_VDPAU(vc->image_format)) {
- rndr = (struct vdpau_render_state *)mpi->planes[0];
- reserved_mpi = mpi;
+ surface = (VdpVideoSurface)(intptr_t)mpi->planes[3];
+ reserved_mpi = mp_image_new_ref(mpi);
} else {
- rndr = get_surface(vo, vc->deint_counter);
+ reserved_mpi = get_video_surface(&vc->mpvdp, IMGFMT_VDPAU,
+ vc->vdp_chroma_type, mpi->w, mpi->h);
+ if (!reserved_mpi)
+ return;
+ surface = (VdpVideoSurface)(intptr_t)reserved_mpi->planes[3];
vc->deint_counter = WRAP_ADD(vc->deint_counter, 1, NUM_BUFFERED_VIDEO);
if (handle_preemption(vo) >= 0) {
VdpStatus vdp_st;
@@ -1257,7 +1209,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
mpi->planes[1]};
if (vc->image_format == IMGFMT_NV12)
destdata[1] = destdata[2];
- vdp_st = vdp->video_surface_put_bits_y_cb_cr(rndr->surface,
+ vdp_st = vdp->video_surface_put_bits_y_cb_cr(surface,
vc->vdp_pixel_format, destdata, mpi->stride);
CHECK_ST_WARNING("Error when calling "
"vdp_video_surface_put_bits_y_cb_cr");
@@ -1268,7 +1220,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
else
vc->top_field_first = 1;
- add_new_video_surface(vo, rndr->surface, reserved_mpi, mpi->pts);
+ add_new_video_surface(vo, surface, reserved_mpi, mpi->pts);
return;
}
@@ -1331,58 +1283,12 @@ static struct mp_image *get_window_screenshot(struct vo *vo)
return image;
}
-static void release_decoder_surface(void *ptr)
-{
- bool *in_use_ptr = ptr;
- *in_use_ptr = false;
-}
-
-static struct mp_image *get_decoder_surface(struct vo *vo)
-{
- struct vdpctx *vc = vo->priv;
-
- if (!IMGFMT_IS_VDPAU(vc->image_format))
- return NULL;
-
- for (int n = 0; n < MAX_VIDEO_SURFACES; n++) {
- if (!vc->surface_in_use[n]) {
- vc->surface_in_use[n] = true;
- struct mp_image *res =
- mp_image_new_custom_ref(&(struct mp_image){0},
- &vc->surface_in_use[n],
- release_decoder_surface);
- mp_image_setfmt(res, vc->image_format);
- mp_image_set_size(res, vc->vid_width, vc->vid_height);
- struct vdpau_render_state *rndr = get_surface(vo, n);
- res->planes[0] = (void *)rndr;
- return res;
- }
- }
-
- mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] no surfaces available in "
- "get_decoder_surface\n");
- // TODO: this probably breaks things forever, provide a dummy buffer?
- return NULL;
-}
static int query_format(struct vo *vo, uint32_t format)
{
- int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW
- | VFCAP_FLIP;
- switch (format) {
- case IMGFMT_420P:
- case IMGFMT_NV12:
- case IMGFMT_YUYV:
- case IMGFMT_UYVY:
- case IMGFMT_VDPAU_MPEG1:
- case IMGFMT_VDPAU_MPEG2:
- case IMGFMT_VDPAU_H264:
- case IMGFMT_VDPAU_WMV3:
- case IMGFMT_VDPAU_VC1:
- case IMGFMT_VDPAU_MPEG4:
- return default_flags;
- }
- return 0;
+ if (!mp_vdpau_get_format(format, NULL, NULL))
+ return 0;
+ return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP;
}
static void destroy_vdpau_objects(struct vo *vo)
@@ -1394,6 +1300,15 @@ static void destroy_vdpau_objects(struct vo *vo)
free_video_specific(vo);
+ for (int i = 0; i < MAX_VIDEO_SURFACES; i++) {
+ // can't hold references past VO lifetime
+ assert(!vc->video_surfaces[i].in_use);
+ if (vc->video_surfaces[i].surface != VDP_INVALID_HANDLE) {
+ vdp_st = vdp->video_surface_destroy(vc->video_surfaces[i].surface);
+ CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
+ }
+ }
+
if (vc->flip_queue != VDP_INVALID_HANDLE) {
vdp_st = vdp->presentation_queue_destroy(vc->flip_queue);
CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy");
@@ -1426,22 +1341,22 @@ static void destroy_vdpau_objects(struct vo *vo)
static void uninit(struct vo *vo)
{
- struct vdpctx *vc = vo->priv;
-
/* Destroy all vdpau objects */
destroy_vdpau_objects(vo);
vo_x11_uninit(vo);
-
- // Free bitstream buffers allocated by FFmpeg
- for (int i = 0; i < MAX_VIDEO_SURFACES; i++)
- av_freep(&vc->surface_render[i].bitstream_buffers);
}
static int preinit(struct vo *vo)
{
struct vdpctx *vc = vo->priv;
+ vc->vdp = talloc_zero(vc, struct vdp_functions);
+ vc->mpvdp.priv = vo;
+ vc->mpvdp.vdp = vc->vdp;
+ vc->mpvdp.status_ok = ctx_status_ok;
+ vc->mpvdp.get_video_surface = get_video_surface;
+
// Mark everything as invalid first so uninit() can tell what has been
// allocated
mark_vdpau_objects_uninitialized(vo);
@@ -1459,7 +1374,7 @@ static int preinit(struct vo *vo)
// After this calling uninit() should work to free resources
if (win_x11_init_vdpau_procs(vo) < 0) {
- if (vc->vdp && vc->vdp->device_destroy)
+ if (vc->vdp->device_destroy)
vc->vdp->device_destroy(vc->vdp_device);
vo_x11_uninit(vo);
return -1;
@@ -1475,13 +1390,6 @@ static int get_equalizer(struct vo *vo, const char *name, int *value)
VO_TRUE : VO_NOTIMPL;
}
-static bool status_ok(struct vo *vo)
-{
- if (!vo->config_ok || handle_preemption(vo) < 0)
- return false;
- return true;
-}
-
static int set_equalizer(struct vo *vo, const char *name, int value)
{
struct vdpctx *vc = vo->priv;
@@ -1534,11 +1442,11 @@ static int control(struct vo *vo, uint32_t request, void *data)
if (vc->dropped_frame)
vo->want_redraw = true;
return true;
- case VOCTRL_HWDEC_ALLOC_SURFACE:
- *(struct mp_image **)data = get_decoder_surface(vo);
+ case VOCTRL_GET_HWDEC_INFO: {
+ struct mp_hwdec_info *arg = data;
+ arg->vdpau_ctx = &vc->mpvdp;
return true;
- case VOCTRL_HWDEC_DECODER_RENDER:
- return decoder_render(vo, data);
+ }
case VOCTRL_GET_PANSCAN:
return VO_TRUE;
case VOCTRL_SET_PANSCAN:
diff --git a/video/vdpau.c b/video/vdpau.c
new file mode 100644
index 0000000000..697bda8447
--- /dev/null
+++ b/video/vdpau.c
@@ -0,0 +1,73 @@
+/*
+ * This file is part of mpv.
+ *
+ * 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 "vdpau.h"
+
+#include "video/img_format.h"
+
+// Check whether vdpau initialization and preemption status is ok and we can
+// proceed normally.
+bool mp_vdpau_status_ok(struct mp_vdpau_ctx *ctx)
+{
+ return ctx->status_ok(ctx);
+}
+
+struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx, int fmt,
+ VdpChromaType chroma, int w, int h)
+{
+ return ctx->get_video_surface(ctx, fmt, chroma, w, h);
+}
+
+bool mp_vdpau_get_format(int imgfmt, VdpChromaType *out_chroma_type,
+ VdpYCbCrFormat *out_pixel_format)
+{
+ VdpChromaType chroma = VDP_CHROMA_TYPE_420;
+ VdpYCbCrFormat ycbcr = (VdpYCbCrFormat)-1;
+
+ switch (imgfmt) {
+ case IMGFMT_420P:
+ ycbcr = VDP_YCBCR_FORMAT_YV12;
+ break;
+ case IMGFMT_NV12:
+ ycbcr = VDP_YCBCR_FORMAT_NV12;
+ break;
+ case IMGFMT_YUYV:
+ ycbcr = VDP_YCBCR_FORMAT_YUYV;
+ chroma = VDP_CHROMA_TYPE_422;
+ break;
+ case IMGFMT_UYVY:
+ ycbcr = VDP_YCBCR_FORMAT_UYVY;
+ chroma = VDP_CHROMA_TYPE_422;
+ break;
+ case IMGFMT_VDPAU_MPEG1:
+ case IMGFMT_VDPAU_MPEG2:
+ case IMGFMT_VDPAU_H264:
+ case IMGFMT_VDPAU_WMV3:
+ case IMGFMT_VDPAU_VC1:
+ case IMGFMT_VDPAU_MPEG4:
+ case IMGFMT_VDPAU:
+ break;
+ default:
+ return false;
+ }
+
+ if (out_chroma_type)
+ *out_chroma_type = chroma;
+ if (out_pixel_format)
+ *out_pixel_format = ycbcr;
+ return true;
+}
diff --git a/video/vdpau.h b/video/vdpau.h
new file mode 100644
index 0000000000..c8a7288b66
--- /dev/null
+++ b/video/vdpau.h
@@ -0,0 +1,55 @@
+#ifndef MPV_VDPAU_H
+#define MPV_VDPAU_H
+
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include <vdpau/vdpau.h>
+#include <vdpau/vdpau_x11.h>
+
+#include "core/mp_msg.h"
+
+#define CHECK_ST_ERROR(message) \
+ do { \
+ if (vdp_st != VDP_STATUS_OK) { \
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
+ message, vdp->get_error_string(vdp_st)); \
+ return -1; \
+ } \
+ } while (0)
+
+#define CHECK_ST_WARNING(message) \
+ do { \
+ if (vdp_st != VDP_STATUS_OK) \
+ mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] %s: %s\n", \
+ message, vdp->get_error_string(vdp_st)); \
+ } while (0)
+
+struct vdp_functions {
+#define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
+#include "video/out/vdpau_template.c"
+#undef VDP_FUNCTION
+};
+
+// Shared state. Objects created from different VdpDevices are often (always?)
+// incompatible to each other, so all code must use a shared VdpDevice.
+struct mp_vdpau_ctx {
+ struct vdp_functions *vdp;
+ VdpDevice vdp_device;
+ bool is_preempted; // set to true during unavailability
+ uint64_t preemption_counter; // incremented after _restoring_
+ bool (*status_ok)(struct mp_vdpau_ctx *ctx);
+ struct mp_image *(*get_video_surface)(struct mp_vdpau_ctx *ctx, int fmt,
+ VdpChromaType chroma, int w, int h);
+ void *priv; // for VO
+};
+
+bool mp_vdpau_status_ok(struct mp_vdpau_ctx *ctx);
+
+struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx, int fmt,
+ VdpChromaType chroma, int w, int h);
+
+bool mp_vdpau_get_format(int imgfmt, VdpChromaType *out_chroma_type,
+ VdpYCbCrFormat *out_pixel_format);
+
+#endif