summaryrefslogtreecommitdiffstats
path: root/video/decode/cuda.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/decode/cuda.c')
-rw-r--r--video/decode/cuda.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/video/decode/cuda.c b/video/decode/cuda.c
new file mode 100644
index 0000000000..f41aed2e7c
--- /dev/null
+++ b/video/decode/cuda.c
@@ -0,0 +1,126 @@
+/*
+ * This file is part of mpv.
+ *
+ * Copyright (c) 2016 Philip Langdale <philipl@overt.org>
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libavutil/hwcontext.h>
+#include <libavutil/hwcontext_cuda.h>
+
+#include "common/av_common.h"
+#include "video/decode/lavc.h"
+
+typedef struct CUVIDContext {
+ CUcontext cuda_ctx;
+} CUVIDContext;
+
+static void cuvid_ctx_free(AVHWDeviceContext *ctx)
+{
+ AVCUDADeviceContext *hwctx = ctx->hwctx;
+ cuCtxDestroy(hwctx->cuda_ctx);
+}
+
+static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
+ const char *codec)
+{
+ if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_CUDA))
+ return HWDEC_ERR_NO_CTX;
+ return 0;
+}
+
+static int init(struct lavc_ctx *ctx)
+{
+ struct CUVIDContext *p = talloc_ptrtype(NULL, p);
+
+ *p = (struct CUVIDContext) {
+ .cuda_ctx = hwdec_devices_get(ctx->hwdec_devs, HWDEC_CUDA)->ctx,
+ };
+ ctx->hwdec_priv = p;
+ return 0;
+}
+
+static int init_decoder(struct lavc_ctx *ctx, int w, int h)
+{
+ AVCodecContext *avctx = ctx->avctx;
+ AVCUDADeviceContext *device_hwctx;
+ AVHWDeviceContext *device_ctx;
+ CUVIDContext *priv = ctx->hwdec_priv;
+ int ret = 0;
+
+ if (avctx->hw_frames_ctx) {
+ MP_ERR(ctx, "hw_frames_ctx already initialised!\n");
+ return -1;
+ }
+
+ AVBufferRef *hw_device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA);
+ if (!hw_device_ctx) {
+ MP_WARN(ctx, "av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA) failed\n");
+ goto error;
+ }
+
+ device_ctx = (AVHWDeviceContext*)hw_device_ctx->data;
+ device_ctx->free = cuvid_ctx_free;
+
+ device_hwctx = device_ctx->hwctx;
+ device_hwctx->cuda_ctx = priv->cuda_ctx;
+
+ ret = av_hwdevice_ctx_init(hw_device_ctx);
+ if (ret < 0) {
+ MP_ERR(ctx, "av_hwdevice_ctx_init failed\n");
+ goto error;
+ }
+
+ avctx->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx);
+ if (!avctx->hw_frames_ctx) {
+ MP_ERR(ctx, "av_hwframe_ctx_alloc failed\n");
+ goto error;
+ }
+
+ return 0;
+
+ error:
+ av_buffer_unref(&avctx->hw_frames_ctx);
+ av_buffer_unref(&hw_device_ctx);
+ return -1;
+}
+
+static void uninit(struct lavc_ctx *ctx)
+{
+ struct CUVIDContext *p = ctx->hwdec_priv;
+ if (!p)
+ return;
+
+ talloc_free(p);
+ ctx->hwdec_priv = NULL;
+}
+
+static struct mp_image *process_image(struct lavc_ctx *ctx, struct mp_image *img)
+{
+ if (img->imgfmt == IMGFMT_CUDA)
+ img->params.hw_subfmt = IMGFMT_NV12;
+ return img;
+}
+
+const struct vd_lavc_hwdec mp_vd_lavc_cuda = {
+ .type = HWDEC_CUDA,
+ .image_format = IMGFMT_CUDA,
+ .lavc_suffix = "_cuvid",
+ .probe = probe,
+ .init = init,
+ .uninit = uninit,
+ .init_decoder = init_decoder,
+ .process_image = process_image,
+};