summaryrefslogtreecommitdiffstats
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;
+}
+