History

lavu: Add DRM hwcontext

Mark Thompson committed 9 years ago

Commit 9cb23cd1 parent 7bae17e11 files · +481 −1Browse files

Unified · Split

11 files
  1. configure +3 −0
  2. doc/APIchanges +3 −0
  3. libavutil/Makefile +2 −0
  4. libavutil/hwcontext.c +4 −0
  5. libavutil/hwcontext.h +1 −0
  6. libavutil/hwcontext_drm.c +289 −0
  7. libavutil/hwcontext_drm.h +166 −0
  8. libavutil/hwcontext_internal.h +1 −0
  9. libavutil/pixdesc.c +4 −0
  10. libavutil/pixfmt.h +7 −0
  11. libavutil/version.h +1 −1
configure+3−0
@@ -307,6 +307,7 @@ External library support: · 306 unmodified lines
307307 --disable-cuvid disable Nvidia CUVID support [autodetect]
308308 --disable-d3d11va disable Microsoft Direct3D 11 video acceleration code [autodetect]
309309 --disable-dxva2 disable Microsoft DirectX 9 video acceleration code [autodetect]
310+ --enable-libdrm enable DRM code (Linux) [no]
310311 --enable-libmfx enable Intel MediaSDK (AKA Quick Sync Video) code via libmfx [no]
311312 --enable-libnpp enable Nvidia Performance Primitives-based code [no]
312313 --enable-mmal enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no]
@@ -1567,6 +1568,7 @@ EXTERNAL_LIBRARY_LIST=" · 1254 unmodified lines
15671568 libcaca
15681569 libcelt
15691570 libdc1394
1571+ libdrm
15701572 libflite
15711573 libfontconfig
15721574 libfreetype
@@ -5877,6 +5879,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && · 4304 unmodified lines
58775879 die "ERROR: libcelt must be installed and version must be >= 0.11.0."; }
58785880 enabled libcaca && require_pkg_config caca caca.h caca_create_canvas
58795881 enabled libdc1394 && require_pkg_config libdc1394-2 dc1394/dc1394.h dc1394_new
5882+enabled libdrm && require_pkg_config libdrm xf86drm.h drmGetVersion
58805883 enabled libfdk_aac && { use_pkg_config fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen ||
58815884 { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac &&
58825885 warn "using libfdk without pkg-config"; } }
doc/APIchanges+3−0
@@ -15,6 +15,9 @@ libavutil: 2015-08-28 · 14 unmodified lines
1515
1616 API changes, most recent first:
1717
18+2017-09-13 - xxxxxxx - lavu 55.75.100 - hwcontext.h hwcontext_drm.h
19+ Add AV_HWDEVICE_TYPE_DRM and implementation.
20+
1821 2017-09-08 - xxxxxxx - lavfi 6.103.100 - buffersrc.h
1922 Add av_buffersrc_close().
2023
libavutil/Makefile+2−0
@@ -34,6 +34,7 @@ HEADERS = adler32.h \ · 33 unmodified lines
3434 hwcontext.h \
3535 hwcontext_cuda.h \
3636 hwcontext_d3d11va.h \
37+ hwcontext_drm.h \
3738 hwcontext_dxva2.h \
3839 hwcontext_qsv.h \
3940 hwcontext_vaapi.h \
@@ -161,6 +162,7 @@ OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o · 121 unmodified lines
161162 OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
162163 OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
163164 OBJS-$(CONFIG_QSV) += hwcontext_qsv.o
165+OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o
164166 OBJS-$(CONFIG_LZO) += lzo.o
165167 OBJS-$(CONFIG_OPENCL) += opencl.o opencl_internal.o
166168 OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o
libavutil/hwcontext.c+4−0
@@ -35,6 +35,9 @@ static const HWContextType *const hw_table[] = { · 34 unmodified lines
3535 #if CONFIG_D3D11VA
3636 &ff_hwcontext_type_d3d11va,
3737 #endif
38+#if CONFIG_LIBDRM
39+ &ff_hwcontext_type_drm,
40+#endif
3841 #if CONFIG_DXVA2
3942 &ff_hwcontext_type_dxva2,
4043 #endif
@@ -55,6 +58,7 @@ static const HWContextType *const hw_table[] = { · 14 unmodified lines
5558
5659 static const char *const hw_type_names[] = {
5760 [AV_HWDEVICE_TYPE_CUDA] = "cuda",
61+ [AV_HWDEVICE_TYPE_DRM] = "drm",
5862 [AV_HWDEVICE_TYPE_DXVA2] = "dxva2",
5963 [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",
6064 [AV_HWDEVICE_TYPE_QSV] = "qsv",
libavutil/hwcontext.h+1−0
@@ -33,6 +33,7 @@ enum AVHWDeviceType { · 32 unmodified lines
3333 AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
3434 AV_HWDEVICE_TYPE_NONE,
3535 AV_HWDEVICE_TYPE_D3D11VA,
36+ AV_HWDEVICE_TYPE_DRM,
3637 };
3738
3839 typedef struct AVHWDeviceInternal AVHWDeviceInternal;
libavutil/hwcontext_drm.c+289−0
@@ -0,0 +1,289 @@
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 <fcntl.h>
20+#include <sys/mman.h>
21+#include <unistd.h>
22+
23+#include <drm.h>
24+#include <xf86drm.h>
25+
26+#include "avassert.h"
27+#include "hwcontext.h"
28+#include "hwcontext_drm.h"
29+#include "hwcontext_internal.h"
30+#include "imgutils.h"
31+
32+
33+static void drm_device_free(AVHWDeviceContext *hwdev)
34+{
35+ AVDRMDeviceContext *hwctx = hwdev->hwctx;
36+
37+ close(hwctx->fd);
38+}
39+
40+static int drm_device_create(AVHWDeviceContext *hwdev, const char *device,
41+ AVDictionary *opts, int flags)
42+{
43+ AVDRMDeviceContext *hwctx = hwdev->hwctx;
44+ drmVersionPtr version;
45+
46+ hwctx->fd = open(device, O_RDWR);
47+ if (hwctx->fd < 0)
48+ return AVERROR(errno);
49+
50+ version = drmGetVersion(hwctx->fd);
51+ if (!version) {
52+ av_log(hwdev, AV_LOG_ERROR, "Failed to get version information "
53+ "from %s: probably not a DRM device?\n", device);
54+ close(hwctx->fd);
55+ return AVERROR(EINVAL);
56+ }
57+
58+ av_log(hwdev, AV_LOG_VERBOSE, "Opened DRM device %s: driver %s "
59+ "version %d.%d.%d.\n", device, version->name,
60+ version->version_major, version->version_minor,
61+ version->version_patchlevel);
62+
63+ drmFreeVersion(version);
64+
65+ hwdev->free = &drm_device_free;
66+
67+ return 0;
68+}
69+
70+static int drm_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
71+{
72+ frame->buf[0] = av_buffer_pool_get(hwfc->pool);
73+ if (!frame->buf[0])
74+ return AVERROR(ENOMEM);
75+
76+ frame->data[0] = (uint8_t*)frame->buf[0]->data;
77+
78+ frame->format = AV_PIX_FMT_DRM_PRIME;
79+ frame->width = hwfc->width;
80+ frame->height = hwfc->height;
81+
82+ return 0;
83+}
84+
85+typedef struct DRMMapping {
86+ // Address and length of each mmap()ed region.
87+ int nb_regions;
88+ void *address[AV_DRM_MAX_PLANES];
89+ size_t length[AV_DRM_MAX_PLANES];
90+} DRMMapping;
91+
92+static void drm_unmap_frame(AVHWFramesContext *hwfc,
93+ HWMapDescriptor *hwmap)
94+{
95+ DRMMapping *map = hwmap->priv;
96+ int i;
97+
98+ for (i = 0; i < map->nb_regions; i++)
99+ munmap(map->address[i], map->length[i]);
100+
101+ av_free(map);
102+}
103+
104+static int drm_map_frame(AVHWFramesContext *hwfc,
105+ AVFrame *dst, const AVFrame *src, int flags)
106+{
107+ const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)src->data[0];
108+ DRMMapping *map;
109+ int err, i, p, plane;
110+ int mmap_prot;
111+ void *addr;
112+
113+ map = av_mallocz(sizeof(*map));
114+ if (!map)
115+ return AVERROR(ENOMEM);
116+
117+ mmap_prot = 0;
118+ if (flags & AV_HWFRAME_MAP_READ)
119+ mmap_prot |= PROT_READ;
120+ if (flags & AV_HWFRAME_MAP_WRITE)
121+ mmap_prot |= PROT_WRITE;
122+
123+ av_assert0(desc->nb_objects <= AV_DRM_MAX_PLANES);
124+ for (i = 0; i < desc->nb_objects; i++) {
125+ addr = mmap(NULL, desc->objects[i].size, mmap_prot, MAP_SHARED,
126+ desc->objects[i].fd, 0);
127+ if (addr == MAP_FAILED) {
128+ err = AVERROR(errno);
129+ av_log(hwfc, AV_LOG_ERROR, "Failed to map DRM object %d to "
130+ "memory: %d.\n", desc->objects[i].fd, errno);
131+ goto fail;
132+ }
133+
134+ map->address[i] = addr;
135+ map->length[i] = desc->objects[i].size;
136+ }
137+ map->nb_regions = i;
138+
139+ plane = 0;
140+ for (i = 0; i < desc->nb_layers; i++) {
141+ const AVDRMLayerDescriptor *layer = &desc->layers[i];
142+ for (p = 0; p < layer->nb_planes; p++) {
143+ dst->data[plane] =
144+ (uint8_t*)map->address[layer->planes[p].object_index] +
145+ layer->planes[p].offset;
146+ dst->linesize[plane] = layer->planes[p].pitch;
147+ ++plane;
148+ }
149+ }
150+ av_assert0(plane <= AV_DRM_MAX_PLANES);
151+
152+ dst->width = src->width;
153+ dst->height = src->height;
154+
155+ err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
156+ &drm_unmap_frame, map);
157+ if (err < 0)
158+ goto fail;
159+
160+ return 0;
161+
162+fail:
163+ for (i = 0; i < desc->nb_objects; i++) {
164+ if (map->address[i])
165+ munmap(map->address[i], map->length[i]);
166+ }
167+ av_free(map);
168+ return err;
169+}
170+
171+static int drm_transfer_get_formats(AVHWFramesContext *ctx,
172+ enum AVHWFrameTransferDirection dir,
173+ enum AVPixelFormat **formats)
174+{
175+ enum AVPixelFormat *pix_fmts;
176+
177+ pix_fmts = av_malloc_array(2, sizeof(*pix_fmts));
178+ if (!pix_fmts)
179+ return AVERROR(ENOMEM);
180+
181+ pix_fmts[0] = ctx->sw_format;
182+ pix_fmts[1] = AV_PIX_FMT_NONE;
183+
184+ *formats = pix_fmts;
185+ return 0;
186+}
187+
188+static int drm_transfer_data_from(AVHWFramesContext *hwfc,
189+ AVFrame *dst, const AVFrame *src)
190+{
191+ AVFrame *map;
192+ int err;
193+
194+ if (dst->width > hwfc->width || dst->height > hwfc->height)
195+ return AVERROR(EINVAL);
196+
197+ map = av_frame_alloc();
198+ if (!map)
199+ return AVERROR(ENOMEM);
200+ map->format = dst->format;
201+
202+ err = drm_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
203+ if (err)
204+ goto fail;
205+
206+ map->width = dst->width;
207+ map->height = dst->height;
208+
209+ err = av_frame_copy(dst, map);
210+ if (err)
211+ goto fail;
212+
213+ err = 0;
214+fail:
215+ av_frame_free(&map);
216+ return err;
217+}
218+
219+static int drm_transfer_data_to(AVHWFramesContext *hwfc,
220+ AVFrame *dst, const AVFrame *src)
221+{
222+ AVFrame *map;
223+ int err;
224+
225+ if (src->width > hwfc->width || src->height > hwfc->height)
226+ return AVERROR(EINVAL);
227+
228+ map = av_frame_alloc();
229+ if (!map)
230+ return AVERROR(ENOMEM);
231+ map->format = src->format;
232+
233+ err = drm_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE |
234+ AV_HWFRAME_MAP_OVERWRITE);
235+ if (err)
236+ goto fail;
237+
238+ map->width = src->width;
239+ map->height = src->height;
240+
241+ err = av_frame_copy(map, src);
242+ if (err)
243+ goto fail;
244+
245+ err = 0;
246+fail:
247+ av_frame_free(&map);
248+ return err;
249+}
250+
251+static int drm_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
252+ const AVFrame *src, int flags)
253+{
254+ int err;
255+
256+ if (hwfc->sw_format != dst->format)
257+ return AVERROR(ENOSYS);
258+
259+ err = drm_map_frame(hwfc, dst, src, flags);
260+ if (err)
261+ return err;
262+
263+ err = av_frame_copy_props(dst, src);
264+ if (err)
265+ return err;
266+
267+ return 0;
268+}
269+
270+const HWContextType ff_hwcontext_type_drm = {
271+ .type = AV_HWDEVICE_TYPE_DRM,
272+ .name = "DRM",
273+
274+ .device_hwctx_size = sizeof(AVDRMDeviceContext),
275+
276+ .device_create = &drm_device_create,
277+
278+ .frames_get_buffer = &drm_get_buffer,
279+
280+ .transfer_get_formats = &drm_transfer_get_formats,
281+ .transfer_data_to = &drm_transfer_data_to,
282+ .transfer_data_from = &drm_transfer_data_from,
283+ .map_from = &drm_map_from,
284+
285+ .pix_fmts = (const enum AVPixelFormat[]) {
286+ AV_PIX_FMT_DRM_PRIME,
287+ AV_PIX_FMT_NONE
288+ },
289+};
libavutil/hwcontext_drm.h+166−0
@@ -0,0 +1,166 @@
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_DRM_H
20+#define AVUTIL_HWCONTEXT_DRM_H
21+
22+#include <stddef.h>
23+#include <stdint.h>
24+
25+/**
26+ * @file
27+ * API-specific header for AV_HWDEVICE_TYPE_DRM.
28+ *
29+ * Internal frame allocation is not currently supported - all frames
30+ * must be allocated by the user. Thus AVHWFramesContext is always
31+ * NULL, though this may change if support for frame allocation is
32+ * added in future.
33+ */
34+
35+enum {
36+ /**
37+ * The maximum number of layers/planes in a DRM frame.
38+ */
39+ AV_DRM_MAX_PLANES = 4
40+};
41+
42+/**
43+ * DRM object descriptor.
44+ *
45+ * Describes a single DRM object, addressing it as a PRIME file
46+ * descriptor.
47+ */
48+typedef struct AVDRMObjectDescriptor {
49+ /**
50+ * DRM PRIME fd for the object.
51+ */
52+ int fd;
53+ /**
54+ * Total size of the object.
55+ *
56+ * (This includes any parts not which do not contain image data.)
57+ */
58+ size_t size;
59+ /**
60+ * Format modifier applied to the object (DRM_FORMAT_MOD_*).
61+ */
62+ uint64_t format_modifier;
63+} AVDRMObjectDescriptor;
64+
65+/**
66+ * DRM plane descriptor.
67+ *
68+ * Describes a single plane of a layer, which is contained within
69+ * a single object.
70+ */
71+typedef struct AVDRMPlaneDescriptor {
72+ /**
73+ * Index of the object containing this plane in the objects
74+ * array of the enclosing frame descriptor.
75+ */
76+ int object_index;
77+ /**
78+ * Offset within that object of this plane.
79+ */
80+ ptrdiff_t offset;
81+ /**
82+ * Pitch (linesize) of this plane.
83+ */
84+ ptrdiff_t pitch;
85+} AVDRMPlaneDescriptor;
86+
87+/**
88+ * DRM layer descriptor.
89+ *
90+ * Describes a single layer within a frame. This has the structure
91+ * defined by its format, and will contain one or more planes.
92+ */
93+typedef struct AVDRMLayerDescriptor {
94+ /**
95+ * Format of the layer (DRM_FORMAT_*).
96+ */
97+ uint32_t format;
98+ /**
99+ * Number of planes in the layer.
100+ *
101+ * This must match the number of planes required by format.
102+ */
103+ int nb_planes;
104+ /**
105+ * Array of planes in this layer.
106+ */
107+ AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES];
108+} AVDRMLayerDescriptor;
109+
110+/**
111+ * DRM frame descriptor.
112+ *
113+ * This is used as the data pointer for AV_PIX_FMT_DRM_PRIME frames.
114+ * It is also used by user-allocated frame pools - allocating in
115+ * AVHWFramesContext.pool must return AVBufferRefs which contain
116+ * an object of this type.
117+ *
118+ * The fields of this structure should be set such it can be
119+ * imported directly by EGL using the EGL_EXT_image_dma_buf_import
120+ * and EGL_EXT_image_dma_buf_import_modifiers extensions.
121+ * (Note that the exact layout of a particular format may vary between
122+ * platforms - we only specify that the same platform should be able
123+ * to import it.)
124+ *
125+ * The total number of planes must not exceed AV_DRM_MAX_PLANES, and
126+ * the order of the planes by increasing layer index followed by
127+ * increasing plane index must be the same as the order which would
128+ * be used for the data pointers in the equivalent software format.
129+ */
130+typedef struct AVDRMFrameDescriptor {
131+ /**
132+ * Number of DRM objects making up this frame.
133+ */
134+ int nb_objects;
135+ /**
136+ * Array of objects making up the frame.
137+ */
138+ AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES];
139+ /**
140+ * Number of layers in the frame.
141+ */
142+ int nb_layers;
143+ /**
144+ * Array of layers in the frame.
145+ */
146+ AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES];
147+} AVDRMFrameDescriptor;
148+
149+/**
150+ * DRM device.
151+ *
152+ * Allocated as AVHWDeviceContext.hwctx.
153+ */
154+typedef struct AVDRMDeviceContext {
155+ /**
156+ * File descriptor of DRM device.
157+ *
158+ * This is used as the device to create frames on, and may also be
159+ * used in some derivation and mapping operations.
160+ *
161+ * If no device is required, set to -1.
162+ */
163+ int fd;
164+} AVDRMDeviceContext;
165+
166+#endif /* AVUTIL_HWCONTEXT_DRM_H */
libavutil/hwcontext_internal.h+1−0
@@ -159,6 +159,7 @@ int ff_hwframe_map_create(AVBufferRef *hwframe_ref, · 158 unmodified lines
159159
160160 extern const HWContextType ff_hwcontext_type_cuda;
161161 extern const HWContextType ff_hwcontext_type_d3d11va;
162+extern const HWContextType ff_hwcontext_type_drm;
162163 extern const HWContextType ff_hwcontext_type_dxva2;
163164 extern const HWContextType ff_hwcontext_type_qsv;
164165 extern const HWContextType ff_hwcontext_type_vaapi;
libavutil/pixdesc.c+4−0
@@ -2237,6 +2237,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { · 2236 unmodified lines
22372237 .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA |
22382238 AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT,
22392239 },
2240+ [AV_PIX_FMT_DRM_PRIME] = {
2241+ .name = "drm_prime",
2242+ .flags = AV_PIX_FMT_FLAG_HWACCEL,
2243+ },
22402244 };
22412245 #if FF_API_PLUS1_MINUS1
22422246 FF_ENABLE_DEPRECATION_WARNINGS
libavutil/pixfmt.h+7−0
@@ -334,6 +334,13 @@ enum AVPixelFormat { · 333 unmodified lines
334334 AV_PIX_FMT_GBRAPF32BE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, big-endian
335335 AV_PIX_FMT_GBRAPF32LE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, little-endian
336336
337+ /**
338+ * DRM-managed buffers exposed through PRIME buffer sharing.
339+ *
340+ * data[0] points to an AVDRMFrameDescriptor.
341+ */
342+ AV_PIX_FMT_DRM_PRIME,
343+
337344 AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
338345 };
339346
libavutil/version.h+1−1
@@ -80,7 +80,7 @@ · 79 unmodified lines
8080
8181
8282 #define LIBAVUTIL_VERSION_MAJOR 55
83−#define LIBAVUTIL_VERSION_MINOR 74
83+#define LIBAVUTIL_VERSION_MINOR 75
8484 #define LIBAVUTIL_VERSION_MICRO 100
8585
8686 #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