summaryrefslogtreecommitdiffstats
path: root/video/decode
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-05-28 21:56:13 +0200
committerwm4 <wm4@nowhere>2015-05-28 21:56:13 +0200
commit6f5a10542c276ad4fa87a2f449dc4173e10fc47d (patch)
treef27fd184990556233bdfb19fb9de21ddc2063219 /video/decode
parent0699a6c598bc1c8968f426be37b62052f7cb1eb9 (diff)
downloadmpv-6f5a10542c276ad4fa87a2f449dc4173e10fc47d.tar.bz2
mpv-6f5a10542c276ad4fa87a2f449dc4173e10fc47d.tar.xz
vdpau: add support for the "new" libavcodec vdpau API
Yet another of these dozens of hwaccel changes. This time, libavcodec provides utility functions, which initialize the vdpau decoder and map codec profiles. So a lot of work the API user had to do falls away. This also will give us support for high bit depth profiles, and possibly HEVC once libavcodec supports it.
Diffstat (limited to 'video/decode')
-rw-r--r--video/decode/lavc.h2
-rw-r--r--video/decode/vd_lavc.c7
-rw-r--r--video/decode/vdpau.c112
3 files changed, 120 insertions, 1 deletions
diff --git a/video/decode/lavc.h b/video/decode/lavc.h
index 7f45499eb1..f37f9cc4e6 100644
--- a/video/decode/lavc.h
+++ b/video/decode/lavc.h
@@ -31,6 +31,8 @@ typedef struct lavc_ctx {
int hwdec_w;
int hwdec_h;
int hwdec_profile;
+
+ bool hwdec_request_reinit;
} vd_ffmpeg_ctx;
struct vd_lavc_hwdec {
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 7c95f00e2c..de917a7820 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -517,11 +517,13 @@ static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx,
ctx->hwdec_w != avctx->coded_width ||
ctx->hwdec_h != avctx->coded_height ||
ctx->hwdec_fmt != ctx->hwdec->image_format ||
- ctx->hwdec_profile != avctx->profile;
+ ctx->hwdec_profile != avctx->profile ||
+ ctx->hwdec_request_reinit;
ctx->hwdec_w = avctx->coded_width;
ctx->hwdec_h = avctx->coded_height;
ctx->hwdec_fmt = ctx->hwdec->image_format;
ctx->hwdec_profile = avctx->profile;
+ ctx->hwdec_request_reinit = false;
if (ctx->hwdec->init_decoder && change) {
if (ctx->hwdec->init_decoder(ctx, ctx->hwdec_fmt,
ctx->hwdec_w, ctx->hwdec_h) < 0)
@@ -620,6 +622,9 @@ static int decode(struct dec_video *vd, struct demux_packet *packet,
return -1;
}
+ if (ctx->hwdec_request_reinit)
+ avcodec_flush_buffers(avctx);
+
// Skipped frame, or delayed output due to multithreaded decoding.
if (!got_picture)
return 0;
diff --git a/video/decode/vdpau.c b/video/decode/vdpau.c
new file mode 100644
index 0000000000..dfa5164ae9
--- /dev/null
+++ b/video/decode/vdpau.c
@@ -0,0 +1,112 @@
+/*
+ * 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 <libavcodec/avcodec.h>
+#include <libavcodec/vdpau.h>
+#include <libavutil/common.h>
+
+#include "lavc.h"
+#include "common/common.h"
+#include "video/vdpau.h"
+#include "video/hwdec.h"
+
+struct priv {
+ struct mp_log *log;
+ struct mp_vdpau_ctx *mpvdp;
+ uint64_t preemption_counter;
+};
+
+static int init_decoder(struct lavc_ctx *ctx, int fmt, int w, int h)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ // During preemption, pretend everything is ok.
+ if (mp_vdpau_handle_preemption(p->mpvdp, &p->preemption_counter) < 0)
+ return 0;
+
+ return av_vdpau_bind_context(ctx->avctx, p->mpvdp->vdp_device,
+ p->mpvdp->get_proc_address,
+ AV_HWACCEL_FLAG_IGNORE_LEVEL |
+ AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH);
+}
+
+static struct mp_image *allocate_image(struct lavc_ctx *ctx, int fmt,
+ int w, int h)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ // In case of preemption, reinit the decoder. Setting hwdec_request_reinit
+ // will cause init_decoder() to be called again.
+ if (mp_vdpau_handle_preemption(p->mpvdp, &p->preemption_counter) == 0)
+ ctx->hwdec_request_reinit = true;
+
+ VdpChromaType chroma = 0;
+ uint32_t s_w = w, s_h = h;
+ if (av_vdpau_get_surface_parameters(ctx->avctx, &chroma, &s_w, &s_h) < 0)
+ return NULL;
+
+ return mp_vdpau_get_video_surface(p->mpvdp, chroma, s_w, s_h);
+}
+
+static void uninit(struct lavc_ctx *ctx)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ talloc_free(p);
+
+ av_freep(&ctx->avctx->hwaccel_context);
+}
+
+static int init(struct lavc_ctx *ctx)
+{
+ struct priv *p = talloc_ptrtype(NULL, p);
+ *p = (struct priv) {
+ .log = mp_log_new(p, ctx->log, "vdpau"),
+ .mpvdp = ctx->hwdec_info->hwctx->vdpau_ctx,
+ };
+ ctx->hwdec_priv = p;
+
+ if (mp_vdpau_handle_preemption(p->mpvdp, &p->preemption_counter) < 1)
+ goto error;
+
+ return 0;
+
+error:
+ uninit(ctx);
+ return -1;
+}
+
+static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+ const char *decoder)
+{
+ hwdec_request_api(info, "vdpau");
+ if (!info || !info->hwctx || !info->hwctx->vdpau_ctx)
+ return HWDEC_ERR_NO_CTX;
+ if (mp_vdpau_guess_if_emulated(info->hwctx->vdpau_ctx))
+ return HWDEC_ERR_EMULATED;
+ return 0;
+}
+
+const struct vd_lavc_hwdec mp_vd_lavc_vdpau = {
+ .type = HWDEC_VDPAU,
+ .image_format = IMGFMT_VDPAU,
+ .probe = probe,
+ .init = init,
+ .uninit = uninit,
+ .init_decoder = init_decoder,
+ .allocate_image = allocate_image,
+};