History

Merge commit 'a001ce31bc2bcf875a39b5fb22dae49120293b42'

* commit 'a001ce31bc2bcf875a39b5fb22dae49120293b42': hwcontext: add a VDPAU implementation

Derek Buitenhuis committed 10 years ago

Commit d779d8d2 parents 1a70878 a001ce36 files · +461 −0Browse files

Unified · Split

6 files
  1. doc/APIchanges +2 −0
  2. libavutil/Makefile +2 −0
  3. libavutil/hwcontext.c +3 −0
  4. libavutil/hwcontext_internal.h +2 −0
  5. libavutil/hwcontext_vdpau.c +408 −0
  6. libavutil/hwcontext_vdpau.h +44 −0
doc/APIchanges+2−0
@@ -19,6 +19,8 @@ API changes, most recent first: · 18 unmodified lines
1919 xxxxxxx buffer.h - Add av_buffer_pool_init2().
2020 xxxxxxx hwcontext.h - Add a new installed header hwcontext.h with a new API
2121 for handling hwaccel frames.
22+ xxxxxxx hwcontext_vdpau.h - Add a new installed header hwcontext_vdpau.h with
23+ VDPAU-specific hwcontext definitions.
2224
2325 -------- 8< --------- FFmpeg 3.0 was cut here -------- 8< ---------
2426
libavutil/Makefile+2−0
@@ -32,6 +32,7 @@ HEADERS = adler32.h \ · 31 unmodified lines
3232 hash.h \
3333 hmac.h \
3434 hwcontext.h \
35+ hwcontext_vdpau.h \
3536 imgutils.h \
3637 intfloat.h \
3738 intreadwrite.h \
@@ -150,6 +151,7 @@ OBJS-$(!HAVE_ATOMICS_NATIVE) += atomic.o \ · 112 unmodified lines
150151
151152 OBJS-$(CONFIG_LZO) += lzo.o
152153 OBJS-$(CONFIG_OPENCL) += opencl.o opencl_internal.o
154+OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o
153155
154156 OBJS += $(COMPAT_OBJS:%=../compat/%)
155157
libavutil/hwcontext.c+3−0
@@ -29,6 +29,9 @@ · 28 unmodified lines
2929 #include "pixfmt.h"
3030
3131 static const HWContextType *hw_table[] = {
32+#if CONFIG_VDPAU
33+ &ff_hwcontext_type_vdpau,
34+#endif
3235 NULL,
3336 };
3437
libavutil/hwcontext_internal.h+2−0
@@ -86,4 +86,6 @@ struct AVHWFramesInternal { · 85 unmodified lines
8686 AVBufferPool *pool_internal;
8787 };
8888
89+extern const HWContextType ff_hwcontext_type_vdpau;
90+
8991 #endif /* AVUTIL_HWCONTEXT_INTERNAL_H */
libavutil/hwcontext_vdpau.c+408−0
@@ -0,0 +1,408 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg 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+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#include <stdint.h>
20+#include <string.h>
21+
22+#include <vdpau/vdpau.h>
23+
24+#include "buffer.h"
25+#include "common.h"
26+#include "hwcontext.h"
27+#include "hwcontext_internal.h"
28+#include "hwcontext_vdpau.h"
29+#include "mem.h"
30+#include "pixfmt.h"
31+#include "pixdesc.h"
32+
33+typedef struct VDPAUDeviceContext {
34+ VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *get_transfer_caps;
35+ VdpVideoSurfaceGetBitsYCbCr *get_data;
36+ VdpVideoSurfacePutBitsYCbCr *put_data;
37+ VdpVideoSurfaceCreate *surf_create;
38+ VdpVideoSurfaceDestroy *surf_destroy;
39+
40+ enum AVPixelFormat *pix_fmts[3];
41+ int nb_pix_fmts[3];
42+} VDPAUDeviceContext;
43+
44+typedef struct VDPAUFramesContext {
45+ VdpVideoSurfaceGetBitsYCbCr *get_data;
46+ VdpVideoSurfacePutBitsYCbCr *put_data;
47+ VdpChromaType chroma_type;
48+ int chroma_idx;
49+
50+ const enum AVPixelFormat *pix_fmts;
51+ int nb_pix_fmts;
52+} VDPAUFramesContext;
53+
54+typedef struct VDPAUPixFmtMap {
55+ VdpYCbCrFormat vdpau_fmt;
56+ enum AVPixelFormat pix_fmt;
57+} VDPAUPixFmtMap;
58+
59+static const VDPAUPixFmtMap pix_fmts_420[] = {
60+ { VDP_YCBCR_FORMAT_NV12, AV_PIX_FMT_NV12 },
61+ { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV420P },
62+ { 0, AV_PIX_FMT_NONE, },
63+};
64+
65+static const VDPAUPixFmtMap pix_fmts_422[] = {
66+ { VDP_YCBCR_FORMAT_NV12, AV_PIX_FMT_NV16 },
67+ { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV422P },
68+ { VDP_YCBCR_FORMAT_UYVY, AV_PIX_FMT_UYVY422 },
69+ { VDP_YCBCR_FORMAT_YUYV, AV_PIX_FMT_YUYV422 },
70+ { 0, AV_PIX_FMT_NONE, },
71+};
72+
73+static const VDPAUPixFmtMap pix_fmts_444[] = {
74+ { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV444P },
75+ { 0, AV_PIX_FMT_NONE, },
76+};
77+
78+static const struct {
79+ VdpChromaType chroma_type;
80+ const VDPAUPixFmtMap *map;
81+} vdpau_pix_fmts[] = {
82+ { VDP_CHROMA_TYPE_420, pix_fmts_420 },
83+ { VDP_CHROMA_TYPE_422, pix_fmts_422 },
84+ { VDP_CHROMA_TYPE_444, pix_fmts_444 },
85+};
86+
87+static int count_pixfmts(const VDPAUPixFmtMap *map)
88+{
89+ int count = 0;
90+ while (map->pix_fmt != AV_PIX_FMT_NONE) {
91+ map++;
92+ count++;
93+ }
94+ return count;
95+}
96+
97+static int vdpau_init_pixmfts(AVHWDeviceContext *ctx)
98+{
99+ AVVDPAUDeviceContext *hwctx = ctx->hwctx;
100+ VDPAUDeviceContext *priv = ctx->internal->priv;
101+ int i;
102+
103+ for (i = 0; i < FF_ARRAY_ELEMS(priv->pix_fmts); i++) {
104+ const VDPAUPixFmtMap *map = vdpau_pix_fmts[i].map;
105+ int nb_pix_fmts;
106+
107+ nb_pix_fmts = count_pixfmts(map);
108+ priv->pix_fmts[i] = av_malloc_array(nb_pix_fmts + 1, sizeof(*priv->pix_fmts[i]));
109+ if (!priv->pix_fmts[i])
110+ return AVERROR(ENOMEM);
111+
112+ nb_pix_fmts = 0;
113+ while (map->pix_fmt != AV_PIX_FMT_NONE) {
114+ VdpBool supported;
115+ VdpStatus err = priv->get_transfer_caps(hwctx->device, vdpau_pix_fmts[i].chroma_type,
116+ map->vdpau_fmt, &supported);
117+ if (err == VDP_STATUS_OK && supported)
118+ priv->pix_fmts[i][nb_pix_fmts++] = map->pix_fmt;
119+ map++;
120+ }
121+ priv->pix_fmts[i][nb_pix_fmts++] = AV_PIX_FMT_NONE;
122+ priv->nb_pix_fmts[i] = nb_pix_fmts;
123+ }
124+
125+ return 0;
126+}
127+
128+static int vdpau_device_init(AVHWDeviceContext *ctx)
129+{
130+ AVVDPAUDeviceContext *hwctx = ctx->hwctx;
131+ VDPAUDeviceContext *priv = ctx->internal->priv;
132+ VdpStatus err;
133+ int ret;
134+
135+#define GET_CALLBACK(id, result) \
136+do { \
137+ void *tmp; \
138+ err = hwctx->get_proc_address(hwctx->device, id, &tmp); \
139+ if (err != VDP_STATUS_OK) { \
140+ av_log(ctx, AV_LOG_ERROR, "Error getting the " #id " callback.\n"); \
141+ return AVERROR_UNKNOWN; \
142+ } \
143+ priv->result = tmp; \
144+} while (0)
145+
146+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES,
147+ get_transfer_caps);
148+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, get_data);
149+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR, put_data);
150+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_CREATE, surf_create);
151+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, surf_destroy);
152+
153+ ret = vdpau_init_pixmfts(ctx);
154+ if (ret < 0) {
155+ av_log(ctx, AV_LOG_ERROR, "Error querying the supported pixel formats\n");
156+ return ret;
157+ }
158+
159+ return 0;
160+}
161+
162+static void vdpau_device_uninit(AVHWDeviceContext *ctx)
163+{
164+ VDPAUDeviceContext *priv = ctx->internal->priv;
165+ int i;
166+
167+ for (i = 0; i < FF_ARRAY_ELEMS(priv->pix_fmts); i++)
168+ av_freep(&priv->pix_fmts[i]);
169+}
170+
171+static void vdpau_buffer_free(void *opaque, uint8_t *data)
172+{
173+ AVHWFramesContext *ctx = opaque;
174+ VDPAUDeviceContext *device_priv = ctx->device_ctx->internal->priv;
175+ VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)data;
176+
177+ device_priv->surf_destroy(surf);
178+}
179+
180+static AVBufferRef *vdpau_pool_alloc(void *opaque, int size)
181+{
182+ AVHWFramesContext *ctx = opaque;
183+ VDPAUFramesContext *priv = ctx->internal->priv;
184+ AVVDPAUDeviceContext *device_hwctx = ctx->device_ctx->hwctx;
185+ VDPAUDeviceContext *device_priv = ctx->device_ctx->internal->priv;
186+
187+ AVBufferRef *ret;
188+ VdpVideoSurface surf;
189+ VdpStatus err;
190+
191+ err = device_priv->surf_create(device_hwctx->device, priv->chroma_type,
192+ ctx->width, ctx->height, &surf);
193+ if (err != VDP_STATUS_OK) {
194+ av_log(ctx, AV_LOG_ERROR, "Error allocating a VDPAU video surface\n");
195+ return NULL;
196+ }
197+
198+ ret = av_buffer_create((uint8_t*)(uintptr_t)surf, sizeof(surf),
199+ vdpau_buffer_free, ctx, AV_BUFFER_FLAG_READONLY);
200+ if (!ret) {
201+ device_priv->surf_destroy(surf);
202+ return NULL;
203+ }
204+
205+ return ret;
206+}
207+
208+static int vdpau_frames_init(AVHWFramesContext *ctx)
209+{
210+ VDPAUDeviceContext *device_priv = ctx->device_ctx->internal->priv;
211+ VDPAUFramesContext *priv = ctx->internal->priv;
212+
213+ int i;
214+
215+ switch (ctx->sw_format) {
216+ case AV_PIX_FMT_YUV420P: priv->chroma_type = VDP_CHROMA_TYPE_420; break;
217+ case AV_PIX_FMT_YUV422P: priv->chroma_type = VDP_CHROMA_TYPE_422; break;
218+ case AV_PIX_FMT_YUV444P: priv->chroma_type = VDP_CHROMA_TYPE_444; break;
219+ default:
220+ av_log(ctx, AV_LOG_ERROR, "Unsupported data layout: %s\n",
221+ av_get_pix_fmt_name(ctx->sw_format));
222+ return AVERROR(ENOSYS);
223+ }
224+
225+ for (i = 0; i < FF_ARRAY_ELEMS(vdpau_pix_fmts); i++) {
226+ if (vdpau_pix_fmts[i].chroma_type == priv->chroma_type) {
227+ priv->chroma_idx = i;
228+ priv->pix_fmts = device_priv->pix_fmts[i];
229+ priv->nb_pix_fmts = device_priv->nb_pix_fmts[i];
230+ break;
231+ }
232+ }
233+ if (!priv->pix_fmts) {
234+ av_log(ctx, AV_LOG_ERROR, "Unsupported chroma type: %d\n", priv->chroma_type);
235+ return AVERROR(ENOSYS);
236+ }
237+
238+ if (!ctx->pool) {
239+ ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(VdpVideoSurface), ctx,
240+ vdpau_pool_alloc, NULL);
241+ if (!ctx->internal->pool_internal)
242+ return AVERROR(ENOMEM);
243+ }
244+
245+ priv->get_data = device_priv->get_data;
246+ priv->put_data = device_priv->put_data;
247+
248+ return 0;
249+}
250+
251+static int vdpau_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
252+{
253+ frame->buf[0] = av_buffer_pool_get(ctx->pool);
254+ if (!frame->buf[0])
255+ return AVERROR(ENOMEM);
256+
257+ frame->data[3] = frame->buf[0]->data;
258+ frame->format = AV_PIX_FMT_VDPAU;
259+ frame->width = ctx->width;
260+ frame->height = ctx->height;
261+
262+ return 0;
263+}
264+
265+static int vdpau_transfer_get_formats(AVHWFramesContext *ctx,
266+ enum AVHWFrameTransferDirection dir,
267+ enum AVPixelFormat **formats)
268+{
269+ VDPAUFramesContext *priv = ctx->internal->priv;
270+
271+ enum AVPixelFormat *fmts;
272+
273+ if (priv->nb_pix_fmts == 1) {
274+ av_log(ctx, AV_LOG_ERROR,
275+ "No target formats are supported for this chroma type\n");
276+ return AVERROR(ENOSYS);
277+ }
278+
279+ fmts = av_malloc_array(priv->nb_pix_fmts, sizeof(*fmts));
280+ if (!fmts)
281+ return AVERROR(ENOMEM);
282+
283+ memcpy(fmts, priv->pix_fmts, sizeof(*fmts) * (priv->nb_pix_fmts));
284+ *formats = fmts;
285+
286+ return 0;
287+}
288+
289+static int vdpau_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
290+ const AVFrame *src)
291+{
292+ VDPAUFramesContext *priv = ctx->internal->priv;
293+ VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
294+
295+ void *data[3];
296+ uint32_t linesize[3];
297+
298+ const VDPAUPixFmtMap *map;
299+ VdpYCbCrFormat vdpau_format;
300+ VdpStatus err;
301+ int i;
302+
303+ for (i = 0; i< FF_ARRAY_ELEMS(data) && dst->data[i]; i++) {
304+ data[i] = dst->data[i];
305+ if (dst->linesize[i] < 0 || (uint64_t)dst->linesize > UINT32_MAX) {
306+ av_log(ctx, AV_LOG_ERROR,
307+ "The linesize %d cannot be represented as uint32\n",
308+ dst->linesize[i]);
309+ return AVERROR(ERANGE);
310+ }
311+ linesize[i] = dst->linesize[i];
312+ }
313+
314+ map = vdpau_pix_fmts[priv->chroma_idx].map;
315+ for (i = 0; map[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
316+ if (map[i].pix_fmt == dst->format) {
317+ vdpau_format = map[i].vdpau_fmt;
318+ break;
319+ }
320+ }
321+ if (map[i].pix_fmt == AV_PIX_FMT_NONE) {
322+ av_log(ctx, AV_LOG_ERROR,
323+ "Unsupported target pixel format: %s\n",
324+ av_get_pix_fmt_name(dst->format));
325+ return AVERROR(EINVAL);
326+ }
327+
328+ if (vdpau_format == VDP_YCBCR_FORMAT_YV12)
329+ FFSWAP(void*, data[1], data[2]);
330+
331+ err = priv->get_data(surf, vdpau_format, data, linesize);
332+ if (err != VDP_STATUS_OK) {
333+ av_log(ctx, AV_LOG_ERROR, "Error retrieving the data from a VDPAU surface\n");
334+ return AVERROR_UNKNOWN;
335+ }
336+
337+ return 0;
338+}
339+
340+static int vdpau_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
341+ const AVFrame *src)
342+{
343+ VDPAUFramesContext *priv = ctx->internal->priv;
344+ VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)dst->data[3];
345+
346+ const void *data[3];
347+ uint32_t linesize[3];
348+
349+ const VDPAUPixFmtMap *map;
350+ VdpYCbCrFormat vdpau_format;
351+ VdpStatus err;
352+ int i;
353+
354+ for (i = 0; i< FF_ARRAY_ELEMS(data) && src->data[i]; i++) {
355+ data[i] = src->data[i];
356+ if (src->linesize[i] < 0 || (uint64_t)src->linesize > UINT32_MAX) {
357+ av_log(ctx, AV_LOG_ERROR,
358+ "The linesize %d cannot be represented as uint32\n",
359+ src->linesize[i]);
360+ return AVERROR(ERANGE);
361+ }
362+ linesize[i] = src->linesize[i];
363+ }
364+
365+ map = vdpau_pix_fmts[priv->chroma_idx].map;
366+ for (i = 0; map[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
367+ if (map[i].pix_fmt == src->format) {
368+ vdpau_format = map[i].vdpau_fmt;
369+ break;
370+ }
371+ }
372+ if (map[i].pix_fmt == AV_PIX_FMT_NONE) {
373+ av_log(ctx, AV_LOG_ERROR,
374+ "Unsupported source pixel format: %s\n",
375+ av_get_pix_fmt_name(src->format));
376+ return AVERROR(EINVAL);
377+ }
378+
379+ if (vdpau_format == VDP_YCBCR_FORMAT_YV12)
380+ FFSWAP(const void*, data[1], data[2]);
381+
382+ err = priv->put_data(surf, vdpau_format, data, linesize);
383+ if (err != VDP_STATUS_OK) {
384+ av_log(ctx, AV_LOG_ERROR, "Error uploading the data to a VDPAU surface\n");
385+ return AVERROR_UNKNOWN;
386+ }
387+
388+ return 0;
389+}
390+
391+const HWContextType ff_hwcontext_type_vdpau = {
392+ .type = AV_HWDEVICE_TYPE_VDPAU,
393+ .name = "VDPAU",
394+
395+ .device_hwctx_size = sizeof(AVVDPAUDeviceContext),
396+ .device_priv_size = sizeof(VDPAUDeviceContext),
397+ .frames_priv_size = sizeof(VDPAUFramesContext),
398+
399+ .device_init = vdpau_device_init,
400+ .device_uninit = vdpau_device_uninit,
401+ .frames_init = vdpau_frames_init,
402+ .frames_get_buffer = vdpau_get_buffer,
403+ .transfer_get_formats = vdpau_transfer_get_formats,
404+ .transfer_data_to = vdpau_transfer_data_to,
405+ .transfer_data_from = vdpau_transfer_data_from,
406+
407+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU, AV_PIX_FMT_NONE },
408+};
libavutil/hwcontext_vdpau.h+44−0
@@ -0,0 +1,44 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg 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+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#ifndef AVUTIL_HWCONTEXT_VDPAU_H
20+#define AVUTIL_HWCONTEXT_VDPAU_H
21+
22+#include <vdpau/vdpau.h>
23+
24+/**
25+ * @file
26+ * An API-specific header for AV_HWDEVICE_TYPE_VDPAU.
27+ *
28+ * This API supports dynamic frame pools. AVHWFramesContext.pool must return
29+ * AVBufferRefs whose data pointer is a VdpVideoSurface.
30+ */
31+
32+/**
33+ * This struct is allocated as AVHWDeviceContext.hwctx
34+ */
35+typedef struct AVVDPAUDeviceContext {
36+ VdpDevice device;
37+ VdpGetProcAddress *get_proc_address;
38+} AVVDPAUDeviceContext;
39+
40+/**
41+ * AVHWFramesContext.hwctx is currently not used
42+ */
43+
44+#endif /* AVUTIL_HWCONTEXT_VDPAU_H */

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