History

hwcontext: add a dxva2 implementation

Anton Khirnov committed 10 years ago

Commit c46db381 parent d338abb8 files · +376 −1Browse files

Unified · Split

8 files
  1. doc/APIchanges +3 −0
  2. libavutil/Makefile +3 −0
  3. libavutil/hwcontext.c +3 −0
  4. libavutil/hwcontext.h +1 −0
  5. libavutil/hwcontext_dxva2.c +292 −0
  6. libavutil/hwcontext_dxva2.h +72 −0
  7. libavutil/hwcontext_internal.h +1 −0
  8. libavutil/version.h +1 −1
doc/APIchanges+3−0
@@ -13,6 +13,9 @@ libavutil: 2015-08-28 · 12 unmodified lines
1313
1414 API changes, most recent first:
1515
16+2016-xx-xx - xxxxxxx - lavu 55.11.0 - hwcontext_dxva2.h
17+ Add new installed header with DXVA2-specific hwcontext definitions.
18+
1619 2016-xx-xx - xxxxxxx - lavu 55.10.0 - opt.h
1720 Add av_opt_copy().
1821
libavutil/Makefile+3−0
@@ -26,6 +26,7 @@ HEADERS = adler32.h \ · 25 unmodified lines
2626 hmac.h \
2727 hwcontext.h \
2828 hwcontext_cuda.h \
29+ hwcontext_dxva2.h \
2930 hwcontext_vaapi.h \
3031 hwcontext_vdpau.h \
3132 imgutils.h \
@@ -108,6 +109,7 @@ OBJS = adler32.o \ · 76 unmodified lines
108109 xtea.o \
109110
110111 OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o
112+OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
111113 OBJS-$(CONFIG_LZO) += lzo.o
112114 OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o
113115 OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o
@@ -115,6 +117,7 @@ OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o · 1 unmodified line
115117 OBJS += $(COMPAT_OBJS:%=../compat/%)
116118
117119 SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda.h
120+SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h
118121 SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
119122 SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h
120123 SKIPHEADERS-$(HAVE_ATOMICS_GCC) += atomic_gcc.h
libavutil/hwcontext.c+3−0
@@ -32,6 +32,9 @@ static const HWContextType *hw_table[] = { · 31 unmodified lines
3232 #if CONFIG_CUDA
3333 &ff_hwcontext_type_cuda,
3434 #endif
35+#if CONFIG_DXVA2
36+ &ff_hwcontext_type_dxva2,
37+#endif
3538 #if CONFIG_VAAPI
3639 &ff_hwcontext_type_vaapi,
3740 #endif
libavutil/hwcontext.h+1−0
@@ -28,6 +28,7 @@ enum AVHWDeviceType { · 27 unmodified lines
2828 AV_HWDEVICE_TYPE_VDPAU,
2929 AV_HWDEVICE_TYPE_CUDA,
3030 AV_HWDEVICE_TYPE_VAAPI,
31+ AV_HWDEVICE_TYPE_DXVA2,
3132 };
3233
3334 typedef struct AVHWDeviceInternal AVHWDeviceInternal;
libavutil/hwcontext_dxva2.c+292−0
@@ -0,0 +1,292 @@
1+/*
2+ * This file is part of Libav.
3+ *
4+ * Libav is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * Libav is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with Libav; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#include <windows.h>
20+
21+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
22+#undef _WIN32_WINNT
23+#define _WIN32_WINNT 0x0600
24+#endif
25+#define DXVA2API_USE_BITFIELDS
26+#define COBJMACROS
27+
28+#include <d3d9.h>
29+#include <dxva2api.h>
30+#include <initguid.h>
31+
32+#include "common.h"
33+#include "hwcontext.h"
34+#include "hwcontext_dxva2.h"
35+#include "hwcontext_internal.h"
36+#include "imgutils.h"
37+#include "pixdesc.h"
38+#include "pixfmt.h"
39+
40+typedef struct DXVA2FramesContext {
41+ IDirect3DSurface9 **surfaces_internal;
42+ int nb_surfaces_used;
43+
44+ HANDLE device_handle;
45+ IDirectXVideoAccelerationService *service;
46+
47+ D3DFORMAT format;
48+} DXVA2FramesContext;
49+
50+static const struct {
51+ D3DFORMAT d3d_format;
52+ enum AVPixelFormat pix_fmt;
53+} supported_formats[] = {
54+ { MKTAG('N', 'V', '1', '2'), AV_PIX_FMT_NV12 },
55+};
56+
57+DEFINE_GUID(video_decoder_service, 0xfc51a551, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02);
58+DEFINE_GUID(video_processor_service, 0xfc51a552, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02);
59+
60+static void dxva2_frames_uninit(AVHWFramesContext *ctx)
61+{
62+ AVDXVA2DeviceContext *device_hwctx = ctx->device_ctx->hwctx;
63+ AVDXVA2FramesContext *frames_hwctx = ctx->hwctx;
64+ DXVA2FramesContext *s = ctx->internal->priv;
65+ int i;
66+
67+ if (frames_hwctx->decoder_to_release)
68+ IDirectXVideoDecoder_Release(frames_hwctx->decoder_to_release);
69+
70+ if (s->surfaces_internal) {
71+ for (i = 0; i < frames_hwctx->nb_surfaces; i++) {
72+ if (s->surfaces_internal[i])
73+ IDirect3DSurface9_Release(s->surfaces_internal[i]);
74+ }
75+ }
76+ av_freep(&s->surfaces_internal);
77+
78+ if (s->service) {
79+ IDirectXVideoAccelerationService_Release(s->service);
80+ s->service = NULL;
81+ }
82+
83+ if (s->device_handle != INVALID_HANDLE_VALUE) {
84+ IDirect3DDeviceManager9_CloseDeviceHandle(device_hwctx->devmgr, s->device_handle);
85+ s->device_handle = INVALID_HANDLE_VALUE;
86+ }
87+}
88+
89+static AVBufferRef *dxva2_pool_alloc(void *opaque, int size)
90+{
91+ AVHWFramesContext *ctx = (AVHWFramesContext*)opaque;
92+ DXVA2FramesContext *s = ctx->internal->priv;
93+ AVDXVA2FramesContext *hwctx = ctx->hwctx;
94+
95+ if (s->nb_surfaces_used < hwctx->nb_surfaces) {
96+ s->nb_surfaces_used++;
97+ return av_buffer_create((uint8_t*)s->surfaces_internal[s->nb_surfaces_used - 1],
98+ sizeof(*hwctx->surfaces), NULL, 0, 0);
99+ }
100+
101+ return NULL;
102+}
103+
104+static int dxva2_init_pool(AVHWFramesContext *ctx)
105+{
106+ AVDXVA2FramesContext *frames_hwctx = ctx->hwctx;
107+ AVDXVA2DeviceContext *device_hwctx = ctx->device_ctx->hwctx;
108+ DXVA2FramesContext *s = ctx->internal->priv;
109+ int decode = (frames_hwctx->surface_type == DXVA2_VideoDecoderRenderTarget);
110+
111+ int i;
112+ HRESULT hr;
113+
114+ if (ctx->initial_pool_size <= 0)
115+ return 0;
116+
117+ hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr, &s->device_handle);
118+ if (FAILED(hr)) {
119+ av_log(ctx, AV_LOG_ERROR, "Failed to open device handle\n");
120+ return AVERROR_UNKNOWN;
121+ }
122+
123+ hr = IDirect3DDeviceManager9_GetVideoService(device_hwctx->devmgr,
124+ s->device_handle,
125+ decode ? &video_decoder_service : &video_processor_service,
126+ (void **)&s->service);
127+ if (FAILED(hr)) {
128+ av_log(ctx, AV_LOG_ERROR, "Failed to create the video service\n");
129+ return AVERROR_UNKNOWN;
130+ }
131+
132+ for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
133+ if (ctx->sw_format == supported_formats[i].pix_fmt) {
134+ s->format = supported_formats[i].d3d_format;
135+ break;
136+ }
137+ }
138+ if (i == FF_ARRAY_ELEMS(supported_formats)) {
139+ av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n",
140+ av_get_pix_fmt_name(ctx->sw_format));
141+ return AVERROR(EINVAL);
142+ }
143+
144+ s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size,
145+ sizeof(*s->surfaces_internal));
146+ if (!s->surfaces_internal)
147+ return AVERROR(ENOMEM);
148+
149+ hr = IDirectXVideoAccelerationService_CreateSurface(s->service,
150+ ctx->width, ctx->height,
151+ ctx->initial_pool_size - 1,
152+ s->format, D3DPOOL_DEFAULT, 0,
153+ frames_hwctx->surface_type,
154+ s->surfaces_internal, NULL);
155+ if (FAILED(hr)) {
156+ av_log(ctx, AV_LOG_ERROR, "Could not create the surfaces\n");
157+ return AVERROR_UNKNOWN;
158+ }
159+
160+ ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(*s->surfaces_internal),
161+ ctx, dxva2_pool_alloc, NULL);
162+ if (!ctx->internal->pool_internal)
163+ return AVERROR(ENOMEM);
164+
165+ frames_hwctx->surfaces = s->surfaces_internal;
166+ frames_hwctx->nb_surfaces = ctx->initial_pool_size;
167+
168+ return 0;
169+}
170+
171+static int dxva2_frames_init(AVHWFramesContext *ctx)
172+{
173+ AVDXVA2FramesContext *hwctx = ctx->hwctx;
174+ DXVA2FramesContext *s = ctx->internal->priv;
175+ int ret;
176+
177+ if (hwctx->surface_type != DXVA2_VideoDecoderRenderTarget &&
178+ hwctx->surface_type != DXVA2_VideoProcessorRenderTarget) {
179+ av_log(ctx, AV_LOG_ERROR, "Unknown surface type: %lu\n",
180+ hwctx->surface_type);
181+ return AVERROR(EINVAL);
182+ }
183+
184+ s->device_handle = INVALID_HANDLE_VALUE;
185+
186+ /* init the frame pool if the caller didn't provide one */
187+ if (!ctx->pool) {
188+ ret = dxva2_init_pool(ctx);
189+ if (ret < 0) {
190+ av_log(ctx, AV_LOG_ERROR, "Error creating an internal frame pool\n");
191+ return ret;
192+ }
193+ }
194+
195+ return 0;
196+}
197+
198+static int dxva2_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
199+{
200+ frame->buf[0] = av_buffer_pool_get(ctx->pool);
201+ if (!frame->buf[0])
202+ return AVERROR(ENOMEM);
203+
204+ frame->data[3] = frame->buf[0]->data;
205+ frame->format = AV_PIX_FMT_DXVA2_VLD;
206+ frame->width = ctx->width;
207+ frame->height = ctx->height;
208+
209+ return 0;
210+}
211+
212+static int dxva2_transfer_get_formats(AVHWFramesContext *ctx,
213+ enum AVHWFrameTransferDirection dir,
214+ enum AVPixelFormat **formats)
215+{
216+ enum AVPixelFormat *fmts;
217+
218+ fmts = av_malloc_array(2, sizeof(*fmts));
219+ if (!fmts)
220+ return AVERROR(ENOMEM);
221+
222+ fmts[0] = ctx->sw_format;
223+ fmts[1] = AV_PIX_FMT_NONE;
224+
225+ *formats = fmts;
226+
227+ return 0;
228+}
229+
230+static int dxva2_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
231+ const AVFrame *src)
232+{
233+ IDirect3DSurface9 *surface;
234+ D3DSURFACE_DESC surfaceDesc;
235+ D3DLOCKED_RECT LockedRect;
236+ HRESULT hr;
237+
238+ int download = !!src->hw_frames_ctx;
239+
240+ surface = (IDirect3DSurface9*)(download ? src->data[3] : dst->data[3]);
241+
242+ hr = IDirect3DSurface9_GetDesc(surface, &surfaceDesc);
243+ if (FAILED(hr)) {
244+ av_log(ctx, AV_LOG_ERROR, "Error getting a surface description\n");
245+ return AVERROR_UNKNOWN;
246+ }
247+
248+ hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL,
249+ download ? D3DLOCK_READONLY : D3DLOCK_DISCARD);
250+ if (FAILED(hr)) {
251+ av_log(ctx, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n");
252+ return AVERROR_UNKNOWN;
253+ }
254+
255+ if (download) {
256+ av_image_copy_plane(dst->data[0], dst->linesize[0],
257+ (uint8_t*)LockedRect.pBits, LockedRect.Pitch,
258+ src->width, src->height);
259+ av_image_copy_plane(dst->data[1], dst->linesize[1],
260+ (uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height,
261+ LockedRect.Pitch, src->width, src->height / 2);
262+ } else {
263+ av_image_copy_plane((uint8_t*)LockedRect.pBits, LockedRect.Pitch,
264+ dst->data[0], dst->linesize[0],
265+ src->width, src->height);
266+ av_image_copy_plane((uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height,
267+ LockedRect.Pitch, dst->data[1], dst->linesize[1],
268+ src->width, src->height / 2);
269+ }
270+
271+ IDirect3DSurface9_UnlockRect(surface);
272+
273+ return 0;
274+}
275+
276+const HWContextType ff_hwcontext_type_dxva2 = {
277+ .type = AV_HWDEVICE_TYPE_DXVA2,
278+ .name = "DXVA2",
279+
280+ .device_hwctx_size = sizeof(AVDXVA2DeviceContext),
281+ .frames_hwctx_size = sizeof(AVDXVA2FramesContext),
282+ .frames_priv_size = sizeof(DXVA2FramesContext),
283+
284+ .frames_init = dxva2_frames_init,
285+ .frames_uninit = dxva2_frames_uninit,
286+ .frames_get_buffer = dxva2_get_buffer,
287+ .transfer_get_formats = dxva2_transfer_get_formats,
288+ .transfer_data_to = dxva2_transfer_data,
289+ .transfer_data_from = dxva2_transfer_data,
290+
291+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_DXVA2_VLD, AV_PIX_FMT_NONE },
292+};
libavutil/hwcontext_dxva2.h+72−0
@@ -0,0 +1,72 @@
1+/*
2+ * This file is part of Libav.
3+ *
4+ * Libav is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * Libav is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with Libav; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+
20+#ifndef AVUTIL_HWCONTEXT_DXVA2_H
21+#define AVUTIL_HWCONTEXT_DXVA2_H
22+
23+/**
24+ * @file
25+ * An API-specific header for AV_HWDEVICE_TYPE_DXVA2.
26+ *
27+ * Only fixed-size pools are supported.
28+ *
29+ * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs
30+ * with the data pointer set to a pointer to IDirect3DSurface9.
31+ */
32+
33+#include <d3d9.h>
34+#include <dxva2api.h>
35+
36+/**
37+ * This struct is allocated as AVHWDeviceContext.hwctx
38+ */
39+typedef struct AVDXVA2DeviceContext {
40+ IDirect3DDeviceManager9 *devmgr;
41+} AVDXVA2DeviceContext;
42+
43+/**
44+ * This struct is allocated as AVHWFramesContext.hwctx
45+ */
46+typedef struct AVDXVA2FramesContext {
47+ /**
48+ * The surface type (e.g. DXVA2_VideoProcessorRenderTarget or
49+ * DXVA2_VideoDecoderRenderTarget). Must be set by the caller.
50+ */
51+ DWORD surface_type;
52+
53+ /**
54+ * The surface pool. When an external pool is not provided by the caller,
55+ * this will be managed (allocated and filled on init, freed on uninit) by
56+ * libavutil.
57+ */
58+ IDirect3DSurface9 **surfaces;
59+ int nb_surfaces;
60+
61+ /**
62+ * Certain drivers require the decoder to be destroyed before the surfaces.
63+ * To allow internally managed pools to work properly in such cases, this
64+ * field is provided.
65+ *
66+ * If it is non-NULL, libavutil will call IDirectXVideoDecoder_Release() on
67+ * it just before the internal surface pool is freed.
68+ */
69+ IDirectXVideoDecoder *decoder_to_release;
70+} AVDXVA2FramesContext;
71+
72+#endif /* AVUTIL_HWCONTEXT_DXVA2_H */
libavutil/hwcontext_internal.h+1−0
@@ -97,6 +97,7 @@ struct AVHWFramesInternal { · 96 unmodified lines
9797 };
9898
9999 extern const HWContextType ff_hwcontext_type_cuda;
100+extern const HWContextType ff_hwcontext_type_dxva2;
100101 extern const HWContextType ff_hwcontext_type_vaapi;
101102 extern const HWContextType ff_hwcontext_type_vdpau;
102103
libavutil/version.h+1−1
@@ -54,7 +54,7 @@ · 53 unmodified lines
5454 */
5555
5656 #define LIBAVUTIL_VERSION_MAJOR 55
57−#define LIBAVUTIL_VERSION_MINOR 10
57+#define LIBAVUTIL_VERSION_MINOR 11
5858 #define LIBAVUTIL_VERSION_MICRO 0
5959
6060 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t