diff options
author | James Almer <jamrial@gmail.com> | 2016-06-26 15:14:17 -0300 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2016-06-26 15:14:17 -0300 |
commit | 104c357b6a3ee181e1d657df68e38c17ba2bda77 (patch) | |
tree | 8de7acbcf90609e153169a3d0c65eba46b93b15c /libavutil | |
parent | b2a74dd629c1ab3318ba0123f8814797a4fea3a4 (diff) | |
parent | e9394ca63dab3434bc8e869de019ecd86cb604ac (diff) | |
download | ffmpeg-104c357b6a3ee181e1d657df68e38c17ba2bda77.tar.gz |
Merge branch 'master' into release/3.1
Merged-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavutil')
-rw-r--r-- | libavutil/hwcontext.c | 36 | ||||
-rw-r--r-- | libavutil/hwcontext.h | 28 | ||||
-rw-r--r-- | libavutil/hwcontext_cuda.c | 44 | ||||
-rw-r--r-- | libavutil/hwcontext_dxva2.c | 133 | ||||
-rw-r--r-- | libavutil/hwcontext_internal.h | 3 | ||||
-rw-r--r-- | libavutil/hwcontext_vaapi.c | 123 | ||||
-rw-r--r-- | libavutil/hwcontext_vdpau.c | 81 | ||||
-rw-r--r-- | libavutil/version.h | 2 |
8 files changed, 449 insertions, 1 deletions
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c index eeeb2880ff..1e9e91329c 100644 --- a/libavutil/hwcontext.c +++ b/libavutil/hwcontext.c @@ -452,3 +452,39 @@ void av_hwframe_constraints_free(AVHWFramesConstraints **constraints) } av_freep(constraints); } + +int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, + const char *device, AVDictionary *opts, int flags) +{ + AVBufferRef *device_ref = NULL; + AVHWDeviceContext *device_ctx; + int ret = 0; + + device_ref = av_hwdevice_ctx_alloc(type); + if (!device_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + device_ctx = (AVHWDeviceContext*)device_ref->data; + + if (!device_ctx->internal->hw_type->device_create) { + ret = AVERROR(ENOSYS); + goto fail; + } + + ret = device_ctx->internal->hw_type->device_create(device_ctx, device, + opts, flags); + if (ret < 0) + goto fail; + + ret = av_hwdevice_ctx_init(device_ref); + if (ret < 0) + goto fail; + + *pdevice_ref = device_ref; + return 0; +fail: + av_buffer_unref(&device_ref); + *pdevice_ref = NULL; + return ret; +} diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h index dc8169903b..4e9da0224d 100644 --- a/libavutil/hwcontext.h +++ b/libavutil/hwcontext.h @@ -242,6 +242,34 @@ AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type); int av_hwdevice_ctx_init(AVBufferRef *ref); /** + * Open a device of the specified type and create an AVHWDeviceContext for it. + * + * This is a convenience function intended to cover the simple cases. Callers + * who need to fine-tune device creation/management should open the device + * manually and then wrap it in an AVHWDeviceContext using + * av_hwdevice_ctx_alloc()/av_hwdevice_ctx_init(). + * + * The returned context is already initialized and ready for use, the caller + * should not call av_hwdevice_ctx_init() on it. The user_opaque/free fields of + * the created AVHWDeviceContext are set by this function and should not be + * touched by the caller. + * + * @param device_ctx On success, a reference to the newly-created device context + * will be written here. The reference is owned by the caller + * and must be released with av_buffer_unref() when no longer + * needed. On failure, NULL will be written to this pointer. + * @param type The type of the device to create. + * @param device A type-specific string identifying the device to open. + * @param opts A dictionary of additional (type-specific) options to use in + * opening the device. The dictionary remains owned by the caller. + * @param flags currently unused + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type, + const char *device, AVDictionary *opts, int flags); + +/** * Allocate an AVHWFramesContext tied to a given device context. * * @param device_ctx a reference to a AVHWDeviceContext. This function will make diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c index 2c5980d619..fa24c5d37b 100644 --- a/libavutil/hwcontext_cuda.c +++ b/libavutil/hwcontext_cuda.c @@ -253,6 +253,49 @@ static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, return 0; } +static void cuda_device_free(AVHWDeviceContext *ctx) +{ + AVCUDADeviceContext *hwctx = ctx->hwctx; + cuCtxDestroy(hwctx->cuda_ctx); +} + +static int cuda_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + AVCUDADeviceContext *hwctx = ctx->hwctx; + CUdevice cu_device; + CUcontext dummy; + CUresult err; + int device_idx = 0; + + if (device) + device_idx = strtol(device, NULL, 0); + + err = cuInit(0); + if (err != CUDA_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "Could not initialize the CUDA driver API\n"); + return AVERROR_UNKNOWN; + } + + err = 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; + } + + err = cuCtxCreate(&hwctx->cuda_ctx, 0, cu_device); + if (err != CUDA_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "Error creating a CUDA context\n"); + return AVERROR_UNKNOWN; + } + + cuCtxPopCurrent(&dummy); + + ctx->free = cuda_device_free; + + return 0; +} + const HWContextType ff_hwcontext_type_cuda = { .type = AV_HWDEVICE_TYPE_CUDA, .name = "CUDA", @@ -260,6 +303,7 @@ const HWContextType ff_hwcontext_type_cuda = { .device_hwctx_size = sizeof(AVCUDADeviceContext), .frames_priv_size = sizeof(CUDAFramesContext), + .device_create = cuda_device_create, .frames_init = cuda_frames_init, .frames_get_buffer = cuda_get_buffer, .transfer_get_formats = cuda_transfer_get_formats, diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c index ccee287ee6..e79254bb34 100644 --- a/libavutil/hwcontext_dxva2.c +++ b/libavutil/hwcontext_dxva2.c @@ -38,6 +38,9 @@ #include "pixdesc.h" #include "pixfmt.h" +typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT); +typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **); + typedef struct DXVA2FramesContext { IDirect3DSurface9 **surfaces_internal; int nb_surfaces_used; @@ -48,6 +51,16 @@ typedef struct DXVA2FramesContext { D3DFORMAT format; } DXVA2FramesContext; +typedef struct DXVA2DevicePriv { + HMODULE d3dlib; + HMODULE dxva2lib; + + HANDLE device_handle; + + IDirect3D9 *d3d9; + IDirect3DDevice9 *d3d9device; +} DXVA2DevicePriv; + static const struct { D3DFORMAT d3d_format; enum AVPixelFormat pix_fmt; @@ -287,6 +300,125 @@ static int dxva2_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, return 0; } +static void dxva2_device_free(AVHWDeviceContext *ctx) +{ + AVDXVA2DeviceContext *hwctx = ctx->hwctx; + DXVA2DevicePriv *priv = ctx->user_opaque; + + if (hwctx->devmgr && priv->device_handle != INVALID_HANDLE_VALUE) + IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, priv->device_handle); + + if (hwctx->devmgr) + IDirect3DDeviceManager9_Release(hwctx->devmgr); + + if (priv->d3d9device) + IDirect3DDevice9_Release(priv->d3d9device); + + if (priv->d3d9) + IDirect3D9_Release(priv->d3d9); + + if (priv->d3dlib) + FreeLibrary(priv->d3dlib); + + if (priv->dxva2lib) + FreeLibrary(priv->dxva2lib); + + av_freep(&ctx->user_opaque); +} + +static int dxva2_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + AVDXVA2DeviceContext *hwctx = ctx->hwctx; + DXVA2DevicePriv *priv; + + pDirect3DCreate9 *createD3D = NULL; + pCreateDeviceManager9 *createDeviceManager = NULL; + D3DPRESENT_PARAMETERS d3dpp = {0}; + D3DDISPLAYMODE d3ddm; + unsigned resetToken = 0; + UINT adapter = D3DADAPTER_DEFAULT; + HRESULT hr; + + if (device) + adapter = atoi(device); + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + ctx->user_opaque = priv; + ctx->free = dxva2_device_free; + + priv->device_handle = INVALID_HANDLE_VALUE; + + priv->d3dlib = LoadLibrary("d3d9.dll"); + if (!priv->d3dlib) { + av_log(ctx, AV_LOG_ERROR, "Failed to load D3D9 library\n"); + return AVERROR_UNKNOWN; + } + priv->dxva2lib = LoadLibrary("dxva2.dll"); + if (!priv->dxva2lib) { + av_log(ctx, AV_LOG_ERROR, "Failed to load DXVA2 library\n"); + return AVERROR_UNKNOWN; + } + + createD3D = (pDirect3DCreate9 *)GetProcAddress(priv->d3dlib, "Direct3DCreate9"); + if (!createD3D) { + av_log(ctx, AV_LOG_ERROR, "Failed to locate Direct3DCreate9\n"); + return AVERROR_UNKNOWN; + } + createDeviceManager = (pCreateDeviceManager9 *)GetProcAddress(priv->dxva2lib, + "DXVA2CreateDirect3DDeviceManager9"); + if (!createDeviceManager) { + av_log(ctx, AV_LOG_ERROR, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n"); + return AVERROR_UNKNOWN; + } + + priv->d3d9 = createD3D(D3D_SDK_VERSION); + if (!priv->d3d9) { + av_log(ctx, AV_LOG_ERROR, "Failed to create IDirect3D object\n"); + return AVERROR_UNKNOWN; + } + + IDirect3D9_GetAdapterDisplayMode(priv->d3d9, adapter, &d3ddm); + d3dpp.Windowed = TRUE; + d3dpp.BackBufferWidth = 640; + d3dpp.BackBufferHeight = 480; + d3dpp.BackBufferCount = 0; + d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.Flags = D3DPRESENTFLAG_VIDEO; + + hr = IDirect3D9_CreateDevice(priv->d3d9, adapter, D3DDEVTYPE_HAL, GetDesktopWindow(), + D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, + &d3dpp, &priv->d3d9device); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device\n"); + return AVERROR_UNKNOWN; + } + + hr = createDeviceManager(&resetToken, &hwctx->devmgr); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device manager\n"); + return AVERROR_UNKNOWN; + } + + hr = IDirect3DDeviceManager9_ResetDevice(hwctx->devmgr, priv->d3d9device, resetToken); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to bind Direct3D device to device manager\n"); + return AVERROR_UNKNOWN; + } + + hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &priv->device_handle); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to open device handle\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + const HWContextType ff_hwcontext_type_dxva2 = { .type = AV_HWDEVICE_TYPE_DXVA2, .name = "DXVA2", @@ -295,6 +427,7 @@ const HWContextType ff_hwcontext_type_dxva2 = { .frames_hwctx_size = sizeof(AVDXVA2FramesContext), .frames_priv_size = sizeof(DXVA2FramesContext), + .device_create = dxva2_device_create, .frames_init = dxva2_frames_init, .frames_uninit = dxva2_frames_uninit, .frames_get_buffer = dxva2_get_buffer, diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h index e62324ccda..cf832fecc9 100644 --- a/libavutil/hwcontext_internal.h +++ b/libavutil/hwcontext_internal.h @@ -64,6 +64,9 @@ typedef struct HWContextType { */ size_t frames_priv_size; + int (*device_create)(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags); + int (*device_init)(AVHWDeviceContext *ctx); void (*device_uninit)(AVHWDeviceContext *ctx); diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c index 7c3e4bd27b..3c1493be9a 100644 --- a/libavutil/hwcontext_vaapi.c +++ b/libavutil/hwcontext_vaapi.c @@ -16,6 +16,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" + +#if HAVE_VAAPI_X11 +# include <va/va_x11.h> +#endif +#if HAVE_VAAPI_DRM +# include <va/va_drm.h> +#endif + +#include <fcntl.h> +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + + #include "avassert.h" #include "buffer.h" #include "common.h" @@ -26,6 +41,14 @@ #include "pixdesc.h" #include "pixfmt.h" +typedef struct VAAPIDevicePriv { +#if HAVE_VAAPI_X11 + Display *x11_display; +#endif + + int drm_fd; +} VAAPIDevicePriv; + typedef struct VAAPISurfaceFormat { enum AVPixelFormat pix_fmt; VAImageFormat image_format; @@ -823,6 +846,105 @@ fail: return err; } +static void vaapi_device_free(AVHWDeviceContext *ctx) +{ + AVVAAPIDeviceContext *hwctx = ctx->hwctx; + VAAPIDevicePriv *priv = ctx->user_opaque; + + if (hwctx->display) + vaTerminate(hwctx->display); + +#if HAVE_VAAPI_X11 + if (priv->x11_display) + XCloseDisplay(priv->x11_display); +#endif + + if (priv->drm_fd >= 0) + close(priv->drm_fd); + + av_freep(&priv); +} + +static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + AVVAAPIDeviceContext *hwctx = ctx->hwctx; + VAAPIDevicePriv *priv; + VADisplay display = 0; + VAStatus vas; + int major, minor; + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + priv->drm_fd = -1; + + ctx->user_opaque = priv; + ctx->free = vaapi_device_free; + +#if HAVE_VAAPI_X11 + if (!display && !(device && device[0] == '/')) { + // Try to open the device as an X11 display. + priv->x11_display = XOpenDisplay(device); + if (!priv->x11_display) { + av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display " + "%s.\n", XDisplayName(device)); + } else { + display = vaGetDisplay(priv->x11_display); + if (!display) { + av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display " + "from X11 display %s.\n", XDisplayName(device)); + return AVERROR_UNKNOWN; + } + + av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via " + "X11 display %s.\n", XDisplayName(device)); + } + } +#endif + +#if HAVE_VAAPI_DRM + if (!display && device) { + // Try to open the device as a DRM path. + priv->drm_fd = open(device, O_RDWR); + if (priv->drm_fd < 0) { + av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n", + device); + } else { + display = vaGetDisplayDRM(priv->drm_fd); + if (!display) { + av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display " + "from DRM device %s.\n", device); + return AVERROR_UNKNOWN; + } + + av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via " + "DRM device %s.\n", device); + } + } +#endif + + if (!display) { + av_log(ctx, AV_LOG_ERROR, "No VA display found for " + "device: %s.\n", device ? device : ""); + return AVERROR(EINVAL); + } + + hwctx->display = display; + + vas = vaInitialize(display, &major, &minor); + if (vas != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI " + "connection: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: " + "version %d.%d\n", major, minor); + + return 0; +} + const HWContextType ff_hwcontext_type_vaapi = { .type = AV_HWDEVICE_TYPE_VAAPI, .name = "VAAPI", @@ -833,6 +955,7 @@ const HWContextType ff_hwcontext_type_vaapi = { .frames_hwctx_size = sizeof(AVVAAPIFramesContext), .frames_priv_size = sizeof(VAAPIFramesContext), + .device_create = &vaapi_device_create, .device_init = &vaapi_device_init, .device_uninit = &vaapi_device_uninit, .frames_get_constraints = &vaapi_frames_get_constraints, diff --git a/libavutil/hwcontext_vdpau.c b/libavutil/hwcontext_vdpau.c index 37b740eaad..2b0fad314c 100644 --- a/libavutil/hwcontext_vdpau.c +++ b/libavutil/hwcontext_vdpau.c @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" + #include <stdint.h> #include <string.h> @@ -388,6 +390,82 @@ static int vdpau_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, return 0; } +#if HAVE_VDPAU_X11 +#include <vdpau/vdpau_x11.h> +#include <X11/Xlib.h> + +typedef struct VDPAUDevicePriv { + VdpDeviceDestroy *device_destroy; + Display *dpy; +} VDPAUDevicePriv; + +static void vdpau_device_free(AVHWDeviceContext *ctx) +{ + AVVDPAUDeviceContext *hwctx = ctx->hwctx; + VDPAUDevicePriv *priv = ctx->user_opaque; + + if (priv->device_destroy) + priv->device_destroy(hwctx->device); + if (priv->dpy) + XCloseDisplay(priv->dpy); + av_freep(&priv); +} + +static int vdpau_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + AVVDPAUDeviceContext *hwctx = ctx->hwctx; + + VDPAUDevicePriv *priv; + VdpStatus err; + VdpGetInformationString *get_information_string; + const char *display, *vendor; + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + ctx->user_opaque = priv; + ctx->free = vdpau_device_free; + + priv->dpy = XOpenDisplay(device); + if (!priv->dpy) { + av_log(ctx, AV_LOG_ERROR, "Cannot open the X11 display %s.\n", + XDisplayName(device)); + return AVERROR_UNKNOWN; + } + display = XDisplayString(priv->dpy); + + err = vdp_device_create_x11(priv->dpy, XDefaultScreen(priv->dpy), + &hwctx->device, &hwctx->get_proc_address); + if (err != VDP_STATUS_OK) { + av_log(ctx, AV_LOG_ERROR, "VDPAU device creation on X11 display %s failed.\n", + display); + return AVERROR_UNKNOWN; + } + +#define GET_CALLBACK(id, result) \ +do { \ + void *tmp; \ + err = hwctx->get_proc_address(hwctx->device, id, &tmp); \ + if (err != VDP_STATUS_OK) { \ + av_log(ctx, AV_LOG_ERROR, "Error getting the " #id " callback.\n"); \ + return AVERROR_UNKNOWN; \ + } \ + result = tmp; \ +} while (0) + + GET_CALLBACK(VDP_FUNC_ID_GET_INFORMATION_STRING, get_information_string); + GET_CALLBACK(VDP_FUNC_ID_DEVICE_DESTROY, priv->device_destroy); + + get_information_string(&vendor); + av_log(ctx, AV_LOG_VERBOSE, "Successfully created a VDPAU device (%s) on " + "X11 display %s\n", vendor, display); + + return 0; +} +#endif + const HWContextType ff_hwcontext_type_vdpau = { .type = AV_HWDEVICE_TYPE_VDPAU, .name = "VDPAU", @@ -396,6 +474,9 @@ const HWContextType ff_hwcontext_type_vdpau = { .device_priv_size = sizeof(VDPAUDeviceContext), .frames_priv_size = sizeof(VDPAUFramesContext), +#if HAVE_VDPAU_X11 + .device_create = vdpau_device_create, +#endif .device_init = vdpau_device_init, .device_uninit = vdpau_device_uninit, .frames_init = vdpau_frames_init, diff --git a/libavutil/version.h b/libavutil/version.h index a282fa864d..aa10622840 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -64,7 +64,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 55 -#define LIBAVUTIL_VERSION_MINOR 26 +#define LIBAVUTIL_VERSION_MINOR 27 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ |