FFmpeg
Loading...
Searching...
No Matches
hwcontext_drm.c
Go to the documentation of this file.
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 "config.h"
20
21#include <fcntl.h>
22#include <sys/mman.h>
23#include <unistd.h>
24
25/* This was introduced in version 4.6. And may not exist all without an
26 * optional package. So to prevent a hard dependency on needing the Linux
27 * kernel headers to compile, make this optional. */
28#if HAVE_LINUX_DMA_BUF_H
29#include <linux/dma-buf.h>
30#include <sys/ioctl.h>
31#endif
32
33#include <drm.h>
34#include <xf86drm.h>
35
36#include "avassert.h"
37#include "hwcontext.h"
38#include "hwcontext_drm.h"
39#include "hwcontext_internal.h"
40#include "imgutils.h"
41#include "mem.h"
42
43
45{
46 AVDRMDeviceContext *hwctx = hwdev->hwctx;
47
48 close(hwctx->fd);
49}
50
51static int drm_device_create(AVHWDeviceContext *hwdev, const char *device,
53{
54 AVDRMDeviceContext *hwctx = hwdev->hwctx;
55 drmVersionPtr version;
56
57 hwctx->fd = open(device, O_RDWR);
58 if (hwctx->fd < 0)
59 return AVERROR(errno);
60
61 version = drmGetVersion(hwctx->fd);
62 if (!version) {
63 av_log(hwdev, AV_LOG_ERROR, "Failed to get version information "
64 "from %s: probably not a DRM device?\n", device);
65 close(hwctx->fd);
66 return AVERROR(EINVAL);
67 }
68
69 av_log(hwdev, AV_LOG_VERBOSE, "Opened DRM device %s: driver %s "
70 "version %d.%d.%d.\n", device, version->name,
71 version->version_major, version->version_minor,
72 version->version_patchlevel);
73
74 drmFreeVersion(version);
75
76 hwdev->free = &drm_device_free;
77
78 return 0;
79}
80
82{
83 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
84 if (!frame->buf[0])
85 return AVERROR(ENOMEM);
86
87 frame->data[0] = (uint8_t*)frame->buf[0]->data;
88
90 frame->width = hwfc->width;
91 frame->height = hwfc->height;
92
93 return 0;
94}
95
96typedef struct DRMMapping {
97 // Address and length of each mmap()ed region.
100 int object[AV_DRM_MAX_PLANES];
103} DRMMapping;
104
106 HWMapDescriptor *hwmap)
107{
108 DRMMapping *map = hwmap->priv;
109
110 for (int i = 0; i < map->nb_regions; i++) {
111#if HAVE_LINUX_DMA_BUF_H
112 struct dma_buf_sync sync = { .flags = DMA_BUF_SYNC_END | map->sync_flags };
113 ioctl(map->object[i], DMA_BUF_IOCTL_SYNC, &sync);
114#endif
115 munmap(map->address[i], map->length[i]);
116 }
117
118 av_free(map);
119}
120
122 AVFrame *dst, const AVFrame *src, int flags)
123{
125#if HAVE_LINUX_DMA_BUF_H
126 struct dma_buf_sync sync_start = { 0 };
127#endif
129 int err, i, p, plane;
130 int mmap_prot;
131 void *addr;
132
133 map = av_mallocz(sizeof(*map));
134 if (!map)
135 return AVERROR(ENOMEM);
136
137 mmap_prot = 0;
139 mmap_prot |= PROT_READ;
141 mmap_prot |= PROT_WRITE;
142
143#if HAVE_LINUX_DMA_BUF_H
145 map->sync_flags |= DMA_BUF_SYNC_READ;
147 map->sync_flags |= DMA_BUF_SYNC_WRITE;
148 sync_start.flags = DMA_BUF_SYNC_START | map->sync_flags;
149#endif
150
151 av_assert0(desc->nb_objects <= AV_DRM_MAX_PLANES);
152 for (i = 0; i < desc->nb_objects; i++) {
153 addr = mmap(NULL, desc->objects[i].size, mmap_prot, MAP_SHARED,
154 desc->objects[i].fd, 0);
155 if (addr == MAP_FAILED) {
156 err = AVERROR(errno);
157 av_log(hwfc, AV_LOG_ERROR, "Failed to map DRM object %d to "
158 "memory: %d.\n", desc->objects[i].fd, errno);
159 goto fail;
160 }
161
162 map->address[i] = addr;
163 map->length[i] = desc->objects[i].size;
164 map->object[i] = desc->objects[i].fd;
165
166#if HAVE_LINUX_DMA_BUF_H
167 /* We're not checking for errors here because the kernel may not
168 * support the ioctl, in which case its okay to carry on */
169 ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_SYNC, &sync_start);
170#endif
171 }
172 map->nb_regions = i;
173
174 plane = 0;
175 for (i = 0; i < desc->nb_layers; i++) {
176 const AVDRMLayerDescriptor *layer = &desc->layers[i];
177 for (p = 0; p < layer->nb_planes; p++) {
178 dst->data[plane] =
179 (uint8_t*)map->address[layer->planes[p].object_index] +
180 layer->planes[p].offset;
181 dst->linesize[plane] = layer->planes[p].pitch;
182 ++plane;
183 }
184 }
186
187 dst->width = src->width;
188 dst->height = src->height;
189
190 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
192 if (err < 0)
193 goto fail;
194
195 return 0;
196
197fail:
198 for (i = 0; i < desc->nb_objects; i++) {
199 if (map->address[i])
200 munmap(map->address[i], map->length[i]);
201 }
202 av_free(map);
203 return err;
204}
205
208 enum AVPixelFormat **formats)
209{
211
212 pix_fmts = av_malloc_array(2, sizeof(*pix_fmts));
213 if (!pix_fmts)
214 return AVERROR(ENOMEM);
215
216 pix_fmts[0] = ctx->sw_format;
218
219 *formats = pix_fmts;
220 return 0;
221}
222
224 AVFrame *dst, const AVFrame *src)
225{
226 AVFrame *map;
227 int err;
228
229 if (dst->width > hwfc->width || dst->height > hwfc->height)
230 return AVERROR(EINVAL);
231
233 if (!map)
234 return AVERROR(ENOMEM);
235 map->format = dst->format;
236
238 if (err)
239 goto fail;
240
241 map->width = dst->width;
242 map->height = dst->height;
243
244 err = av_frame_copy(dst, map);
245 if (err)
246 goto fail;
247
248 err = 0;
249fail:
251 return err;
252}
253
255 AVFrame *dst, const AVFrame *src)
256{
257 AVFrame *map;
258 int err;
259
260 if (src->width > hwfc->width || src->height > hwfc->height)
261 return AVERROR(EINVAL);
262
264 if (!map)
265 return AVERROR(ENOMEM);
266 map->format = src->format;
267
270 if (err)
271 goto fail;
272
273 map->width = src->width;
274 map->height = src->height;
275
276 err = av_frame_copy(map, src);
277 if (err)
278 goto fail;
279
280 err = 0;
281fail:
283 return err;
284}
285
287 const AVFrame *src, int flags)
288{
289 int err;
290
291 if (dst->format == AV_PIX_FMT_NONE)
292 dst->format = hwfc->sw_format;
293 else if (hwfc->sw_format != dst->format)
294 return AVERROR(ENOSYS);
295
296 err = drm_map_frame(hwfc, dst, src, flags);
297 if (err)
298 return err;
299
301 if (err)
302 return err;
303
304 return 0;
305}
306
308 .type = AV_HWDEVICE_TYPE_DRM,
309 .name = "DRM",
310
311 .device_hwctx_size = sizeof(AVDRMDeviceContext),
312
313 .device_create = &drm_device_create,
314
315 .frames_get_buffer = &drm_get_buffer,
316
317 .transfer_get_formats = &drm_transfer_get_formats,
318 .transfer_data_to = &drm_transfer_data_to,
319 .transfer_data_from = &drm_transfer_data_from,
320 .map_from = &drm_map_from,
321
322 .pix_fmts = (const enum AVPixelFormat[]) {
325 },
326};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static AVFormatContext * ctx
static AVDictionary * opts
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define NULL
Definition coverity.c:32
static AVFrame * frame
#define fail
Definition test.h:479
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition buffer.c:390
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition frame.c:711
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
int ff_hwframe_map_create(AVBufferRef *hwframe_ref, AVFrame *dst, const AVFrame *src, void(*unmap)(AVHWFramesContext *ctx, HWMapDescriptor *hwmap), void *priv)
Definition hwcontext.c:741
@ AV_HWFRAME_MAP_READ
The mapping must be readable.
Definition hwcontext.h:515
@ AV_HWFRAME_MAP_WRITE
The mapping must be writeable.
Definition hwcontext.h:519
@ AV_HWFRAME_MAP_OVERWRITE
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition hwcontext.h:525
AVHWFrameTransferDirection
Definition hwcontext.h:406
@ AV_HWDEVICE_TYPE_DRM
Definition hwcontext.h:36
static int drm_map_frame(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static int drm_transfer_get_formats(AVHWFramesContext *ctx, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
static int drm_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
static void drm_device_free(AVHWDeviceContext *hwdev)
static void drm_unmap_frame(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
static int drm_device_create(AVHWDeviceContext *hwdev, const char *device, AVDictionary *opts, int flags)
const HWContextType ff_hwcontext_type_drm
static int drm_map_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static int drm_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
static int drm_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
API-specific header for AV_HWDEVICE_TYPE_DRM.
@ AV_DRM_MAX_PLANES
The maximum number of layers/planes in a DRM frame.
const VDPAUPixFmtMap * map
misc image utilities
version
Definition libkvazaar.c:313
static enum AVPixelFormat pix_fmts[]
Definition libkvazaar.c:296
const char * desc
Definition libsvtav1.c:83
Memory handling functions.
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_DRM_PRIME
DRM-managed buffers exposed through PRIME buffer sharing.
Definition pixfmt.h:351
formats
Definition signature.h:47
int fd
File descriptor of DRM device.
DRM frame descriptor.
DRM layer descriptor.
AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]
Array of planes in this layer.
int nb_planes
Number of planes in the layer.
ptrdiff_t pitch
Pitch (linesize) of this plane.
int object_index
Index of the object containing this plane in the objects array of the enclosing frame descriptor.
ptrdiff_t offset
Offset within that object of this plane.
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition hwcontext.h:63
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition hwcontext.h:88
void(* free)(struct AVHWDeviceContext *ctx)
This field may be set by the caller before calling av_hwdevice_ctx_init().
Definition hwcontext.h:100
This struct describes a set or pool of "hardware" frames (i.e.
Definition hwcontext.h:118
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition hwcontext.h:213
int width
The allocated dimensions of the frames in this pool.
Definition hwcontext.h:220
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition hwcontext.h:181
void * address[AV_DRM_MAX_PLANES]
size_t length[AV_DRM_MAX_PLANES]
void * priv
Hardware-specific private data associated with the mapping.
#define av_free(p)
#define av_malloc_array(a, b)
#define av_mallocz(s)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248