diff options
Diffstat (limited to 'libavutil/hwcontext_cuda.c')
-rw-r--r-- | libavutil/hwcontext_cuda.c | 206 |
1 files changed, 141 insertions, 65 deletions
diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c index 260783426a..ed595c3e0f 100644 --- a/libavutil/hwcontext_cuda.c +++ b/libavutil/hwcontext_cuda.c @@ -1,18 +1,18 @@ /* - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg 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. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -20,11 +20,13 @@ #include "common.h" #include "hwcontext.h" #include "hwcontext_internal.h" -#include "hwcontext_cuda.h" +#include "hwcontext_cuda_internal.h" #include "mem.h" #include "pixdesc.h" #include "pixfmt.h" +#define CUDA_FRAME_ALIGNMENT 256 + typedef struct CUDAFramesContext { int shift_width, shift_height; } CUDAFramesContext; @@ -32,59 +34,87 @@ typedef struct CUDAFramesContext { static const enum AVPixelFormat supported_formats[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, - AV_PIX_FMT_P010, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_P010, + AV_PIX_FMT_P016, }; +static int cuda_frames_get_constraints(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + int i; + + constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1, + sizeof(*constraints->valid_sw_formats)); + if (!constraints->valid_sw_formats) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) + constraints->valid_sw_formats[i] = supported_formats[i]; + constraints->valid_sw_formats[FF_ARRAY_ELEMS(supported_formats)] = AV_PIX_FMT_NONE; + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) + return AVERROR(ENOMEM); + + constraints->valid_hw_formats[0] = AV_PIX_FMT_CUDA; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; +} + static void cuda_buffer_free(void *opaque, uint8_t *data) { AVHWFramesContext *ctx = opaque; AVCUDADeviceContext *hwctx = ctx->device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; CUcontext dummy; - cuCtxPushCurrent(hwctx->cuda_ctx); + cu->cuCtxPushCurrent(hwctx->cuda_ctx); - cuMemFree((CUdeviceptr)data); + cu->cuMemFree((CUdeviceptr)data); - cuCtxPopCurrent(&dummy); + cu->cuCtxPopCurrent(&dummy); } static AVBufferRef *cuda_pool_alloc(void *opaque, int size) { AVHWFramesContext *ctx = opaque; AVCUDADeviceContext *hwctx = ctx->device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; AVBufferRef *ret = NULL; CUcontext dummy = NULL; CUdeviceptr data; CUresult err; - err = cuCtxPushCurrent(hwctx->cuda_ctx); + err = cu->cuCtxPushCurrent(hwctx->cuda_ctx); if (err != CUDA_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Error setting current CUDA context\n"); return NULL; } - err = cuMemAlloc(&data, size); + err = cu->cuMemAlloc(&data, size); if (err != CUDA_SUCCESS) goto fail; ret = av_buffer_create((uint8_t*)data, size, cuda_buffer_free, ctx, 0); if (!ret) { - cuMemFree(data); + cu->cuMemFree(data); goto fail; } fail: - cuCtxPopCurrent(&dummy); + cu->cuCtxPopCurrent(&dummy); return ret; } static int cuda_frames_init(AVHWFramesContext *ctx) { CUDAFramesContext *priv = ctx->internal->priv; + int aligned_width = FFALIGN(ctx->width, CUDA_FRAME_ALIGNMENT); int i; for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { @@ -105,17 +135,16 @@ static int cuda_frames_init(AVHWFramesContext *ctx) switch (ctx->sw_format) { case AV_PIX_FMT_NV12: case AV_PIX_FMT_YUV420P: - size = ctx->width * ctx->height * 3 / 2; - break; - case AV_PIX_FMT_P010: - size = ctx->width * ctx->height * 3; + size = aligned_width * ctx->height * 3 / 2; break; case AV_PIX_FMT_YUV444P: - size = ctx->width * ctx->height * 3; - break; - case AV_PIX_FMT_YUV444P16: - size = ctx->width * ctx->height * 6; + case AV_PIX_FMT_P010: + case AV_PIX_FMT_P016: + size = aligned_width * ctx->height * 3; break; + default: + av_log(ctx, AV_LOG_ERROR, "BUG: Pixel format missing from size calculation."); + return AVERROR_BUG; } ctx->internal->pool_internal = av_buffer_pool_init2(size, ctx, cuda_pool_alloc, NULL); @@ -128,46 +157,43 @@ static int cuda_frames_init(AVHWFramesContext *ctx) static int cuda_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) { + int aligned_width; + int width_in_bytes = ctx->width; + + if (ctx->sw_format == AV_PIX_FMT_P010 || + ctx->sw_format == AV_PIX_FMT_P016) { + width_in_bytes *= 2; + } + aligned_width = FFALIGN(width_in_bytes, CUDA_FRAME_ALIGNMENT); + frame->buf[0] = av_buffer_pool_get(ctx->pool); if (!frame->buf[0]) return AVERROR(ENOMEM); switch (ctx->sw_format) { case AV_PIX_FMT_NV12: + case AV_PIX_FMT_P010: + case AV_PIX_FMT_P016: frame->data[0] = frame->buf[0]->data; - frame->data[1] = frame->data[0] + ctx->width * ctx->height; - frame->linesize[0] = ctx->width; - frame->linesize[1] = ctx->width; + frame->data[1] = frame->data[0] + aligned_width * ctx->height; + frame->linesize[0] = aligned_width; + frame->linesize[1] = aligned_width; break; case AV_PIX_FMT_YUV420P: frame->data[0] = frame->buf[0]->data; - frame->data[2] = frame->data[0] + ctx->width * ctx->height; - frame->data[1] = frame->data[2] + ctx->width * ctx->height / 4; - frame->linesize[0] = ctx->width; - frame->linesize[1] = ctx->width / 2; - frame->linesize[2] = ctx->width / 2; - break; - case AV_PIX_FMT_P010: - frame->data[0] = frame->buf[0]->data; - frame->data[1] = frame->data[0] + 2 * ctx->width * ctx->height; - frame->linesize[0] = 2 * ctx->width; - frame->linesize[1] = 2 * ctx->width; + frame->data[2] = frame->data[0] + aligned_width * ctx->height; + frame->data[1] = frame->data[2] + aligned_width * ctx->height / 4; + frame->linesize[0] = aligned_width; + frame->linesize[1] = aligned_width / 2; + frame->linesize[2] = aligned_width / 2; break; case AV_PIX_FMT_YUV444P: frame->data[0] = frame->buf[0]->data; - frame->data[1] = frame->data[0] + ctx->width * ctx->height; - frame->data[2] = frame->data[1] + ctx->width * ctx->height; - frame->linesize[0] = ctx->width; - frame->linesize[1] = ctx->width; - frame->linesize[2] = ctx->width; - break; - case AV_PIX_FMT_YUV444P16: - frame->data[0] = frame->buf[0]->data; - frame->data[1] = frame->data[0] + 2 * ctx->width * ctx->height; - frame->data[2] = frame->data[1] + 2 * ctx->width * ctx->height; - frame->linesize[0] = 2 * ctx->width; - frame->linesize[1] = 2 * ctx->width; - frame->linesize[2] = 2 * ctx->width; + frame->data[1] = frame->data[0] + aligned_width * ctx->height; + frame->data[2] = frame->data[1] + aligned_width * ctx->height; + frame->linesize[0] = aligned_width; + frame->linesize[1] = aligned_width; + frame->linesize[2] = aligned_width; break; default: av_frame_unref(frame); @@ -204,12 +230,13 @@ static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, { CUDAFramesContext *priv = ctx->internal->priv; AVCUDADeviceContext *device_hwctx = ctx->device_ctx->hwctx; + CudaFunctions *cu = device_hwctx->internal->cuda_dl; CUcontext dummy; CUresult err; int i; - err = cuCtxPushCurrent(device_hwctx->cuda_ctx); + err = cu->cuCtxPushCurrent(device_hwctx->cuda_ctx); if (err != CUDA_SUCCESS) return AVERROR_UNKNOWN; @@ -225,14 +252,14 @@ static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, .Height = src->height >> (i ? priv->shift_height : 0), }; - err = cuMemcpy2D(&cpy); + err = cu->cuMemcpy2D(&cpy); if (err != CUDA_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Error transferring the data from the CUDA frame\n"); return AVERROR_UNKNOWN; } } - cuCtxPopCurrent(&dummy); + cu->cuCtxPopCurrent(&dummy); return 0; } @@ -242,12 +269,13 @@ static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, { CUDAFramesContext *priv = ctx->internal->priv; AVCUDADeviceContext *device_hwctx = ctx->device_ctx->hwctx; + CudaFunctions *cu = device_hwctx->internal->cuda_dl; CUcontext dummy; CUresult err; int i; - err = cuCtxPushCurrent(device_hwctx->cuda_ctx); + err = cu->cuCtxPushCurrent(device_hwctx->cuda_ctx); if (err != CUDA_SUCCESS) return AVERROR_UNKNOWN; @@ -263,28 +291,64 @@ static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, .Height = src->height >> (i ? priv->shift_height : 0), }; - err = cuMemcpy2D(&cpy); + err = cu->cuMemcpy2D(&cpy); if (err != CUDA_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Error transferring the data from the CUDA frame\n"); return AVERROR_UNKNOWN; } } - cuCtxPopCurrent(&dummy); + cu->cuCtxPopCurrent(&dummy); return 0; } -static void cuda_device_free(AVHWDeviceContext *ctx) +static void cuda_device_uninit(AVHWDeviceContext *ctx) { AVCUDADeviceContext *hwctx = ctx->hwctx; - cuCtxDestroy(hwctx->cuda_ctx); + + if (hwctx->internal) { + if (hwctx->internal->is_allocated && hwctx->cuda_ctx) { + hwctx->internal->cuda_dl->cuCtxDestroy(hwctx->cuda_ctx); + hwctx->cuda_ctx = NULL; + } + cuda_free_functions(&hwctx->internal->cuda_dl); + } + + av_freep(&hwctx->internal); +} + +static int cuda_device_init(AVHWDeviceContext *ctx) +{ + AVCUDADeviceContext *hwctx = ctx->hwctx; + int ret; + + if (!hwctx->internal) { + hwctx->internal = av_mallocz(sizeof(*hwctx->internal)); + if (!hwctx->internal) + return AVERROR(ENOMEM); + } + + if (!hwctx->internal->cuda_dl) { + ret = cuda_load_functions(&hwctx->internal->cuda_dl); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Could not dynamically load CUDA\n"); + goto error; + } + } + + return 0; + +error: + cuda_device_uninit(ctx); + return ret; } static int cuda_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags) { AVCUDADeviceContext *hwctx = ctx->hwctx; + CudaFunctions *cu; CUdevice cu_device; CUcontext dummy; CUresult err; @@ -293,29 +357,38 @@ static int cuda_device_create(AVHWDeviceContext *ctx, const char *device, if (device) device_idx = strtol(device, NULL, 0); - err = cuInit(0); + if (cuda_device_init(ctx) < 0) + goto error; + + cu = hwctx->internal->cuda_dl; + + err = cu->cuInit(0); if (err != CUDA_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Could not initialize the CUDA driver API\n"); - return AVERROR_UNKNOWN; + goto error; } - err = cuDeviceGet(&cu_device, device_idx); + err = cu->cuDeviceGet(&cu_device, device_idx); if (err != CUDA_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Could not get the device number %d\n", device_idx); - return AVERROR_UNKNOWN; + goto error; } - err = cuCtxCreate(&hwctx->cuda_ctx, 0, cu_device); + err = cu->cuCtxCreate(&hwctx->cuda_ctx, CU_CTX_SCHED_BLOCKING_SYNC, cu_device); if (err != CUDA_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Error creating a CUDA context\n"); - return AVERROR_UNKNOWN; + goto error; } - cuCtxPopCurrent(&dummy); + cu->cuCtxPopCurrent(&dummy); - ctx->free = cuda_device_free; + hwctx->internal->is_allocated = 1; return 0; + +error: + cuda_device_uninit(ctx); + return AVERROR_UNKNOWN; } const HWContextType ff_hwcontext_type_cuda = { @@ -326,6 +399,9 @@ const HWContextType ff_hwcontext_type_cuda = { .frames_priv_size = sizeof(CUDAFramesContext), .device_create = cuda_device_create, + .device_init = cuda_device_init, + .device_uninit = cuda_device_uninit, + .frames_get_constraints = cuda_frames_get_constraints, .frames_init = cuda_frames_init, .frames_get_buffer = cuda_get_buffer, .transfer_get_formats = cuda_transfer_get_formats, |