2 * This file is part of FFmpeg.
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.
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.
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
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>
37 #include "hwcontext.h"
38 #include "hwcontext_drm.h"
39 #include "hwcontext_internal.h"
44 static void drm_device_free(AVHWDeviceContext
*hwdev
)
46 AVDRMDeviceContext
*hwctx
= hwdev
->hwctx
;
51 static int drm_device_create(AVHWDeviceContext
*hwdev
, const char *device
,
52 AVDictionary
*opts
, int flags
)
54 AVDRMDeviceContext
*hwctx
= hwdev
->hwctx
;
55 drmVersionPtr version
;
57 hwctx
->fd
= open(device
, O_RDWR
);
59 return AVERROR(errno
);
61 version
= drmGetVersion(hwctx
->fd
);
63 av_log(hwdev
, AV_LOG_ERROR
, "Failed to get version information "
64 "from %s: probably not a DRM device?\n", device
);
66 return AVERROR(EINVAL
);
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
);
74 drmFreeVersion(version
);
76 hwdev
->free
= &drm_device_free
;
81 static int drm_get_buffer(AVHWFramesContext
*hwfc
, AVFrame
*frame
)
83 frame
->buf
[0] = av_buffer_pool_get(hwfc
->pool
);
85 return AVERROR(ENOMEM
);
87 frame
->data
[0] = (uint8_t*)frame
->buf
[0]->data
;
89 frame
->format
= AV_PIX_FMT_DRM_PRIME
;
90 frame
->width
= hwfc
->width
;
91 frame
->height
= hwfc
->height
;
96 typedef struct DRMMapping
{
97 // Address and length of each mmap()ed region.
100 int object
[AV_DRM_MAX_PLANES
];
101 void *address
[AV_DRM_MAX_PLANES
];
102 size_t length
[AV_DRM_MAX_PLANES
];
105 static void drm_unmap_frame(AVHWFramesContext
*hwfc
,
106 HWMapDescriptor
*hwmap
)
108 DRMMapping
*map
= hwmap
->priv
;
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
);
115 munmap(map
->address
[i
], map
->length
[i
]);
121 static int drm_map_frame(AVHWFramesContext
*hwfc
,
122 AVFrame
*dst
, const AVFrame
*src
, int flags
)
124 const AVDRMFrameDescriptor
*desc
= (AVDRMFrameDescriptor
*)src
->data
[0];
125 #if HAVE_LINUX_DMA_BUF_H
126 struct dma_buf_sync sync_start
= { 0 };
129 int err
, i
, p
, plane
;
133 map
= av_mallocz(sizeof(*map
));
135 return AVERROR(ENOMEM
);
138 if (flags
& AV_HWFRAME_MAP_READ
)
139 mmap_prot
|= PROT_READ
;
140 if (flags
& AV_HWFRAME_MAP_WRITE
)
141 mmap_prot
|= PROT_WRITE
;
143 #if HAVE_LINUX_DMA_BUF_H
144 if (flags
& AV_HWFRAME_MAP_READ
)
145 map
->sync_flags
|= DMA_BUF_SYNC_READ
;
146 if (flags
& AV_HWFRAME_MAP_WRITE
)
147 map
->sync_flags
|= DMA_BUF_SYNC_WRITE
;
148 sync_start
.flags
= DMA_BUF_SYNC_START
| map
->sync_flags
;
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
);
162 map
->address
[i
] = addr
;
163 map
->length
[i
] = desc
->objects
[i
].size
;
164 map
->object
[i
] = desc
->objects
[i
].fd
;
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
);
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
++) {
179 (uint8_t*)map
->address
[layer
->planes
[p
].object_index
] +
180 layer
->planes
[p
].offset
;
181 dst
->linesize
[plane
] = layer
->planes
[p
].pitch
;
185 av_assert0(plane
<= AV_DRM_MAX_PLANES
);
187 dst
->width
= src
->width
;
188 dst
->height
= src
->height
;
190 err
= ff_hwframe_map_create(src
->hw_frames_ctx
, dst
, src
,
191 &drm_unmap_frame
, map
);
198 for (i
= 0; i
< desc
->nb_objects
; i
++) {
200 munmap(map
->address
[i
], map
->length
[i
]);
206 static int drm_transfer_get_formats(AVHWFramesContext
*ctx
,
207 enum AVHWFrameTransferDirection dir
,
208 enum AVPixelFormat
**formats
)
210 enum AVPixelFormat
*pix_fmts
;
212 pix_fmts
= av_malloc_array(2, sizeof(*pix_fmts
));
214 return AVERROR(ENOMEM
);
216 pix_fmts
[0] = ctx
->sw_format
;
217 pix_fmts
[1] = AV_PIX_FMT_NONE
;
223 static int drm_transfer_data_from(AVHWFramesContext
*hwfc
,
224 AVFrame
*dst
, const AVFrame
*src
)
229 if (dst
->width
> hwfc
->width
|| dst
->height
> hwfc
->height
)
230 return AVERROR(EINVAL
);
232 map
= av_frame_alloc();
234 return AVERROR(ENOMEM
);
235 map
->format
= dst
->format
;
237 err
= drm_map_frame(hwfc
, map
, src
, AV_HWFRAME_MAP_READ
);
241 map
->width
= dst
->width
;
242 map
->height
= dst
->height
;
244 err
= av_frame_copy(dst
, map
);
254 static int drm_transfer_data_to(AVHWFramesContext
*hwfc
,
255 AVFrame
*dst
, const AVFrame
*src
)
260 if (src
->width
> hwfc
->width
|| src
->height
> hwfc
->height
)
261 return AVERROR(EINVAL
);
263 map
= av_frame_alloc();
265 return AVERROR(ENOMEM
);
266 map
->format
= src
->format
;
268 err
= drm_map_frame(hwfc
, map
, dst
, AV_HWFRAME_MAP_WRITE
|
269 AV_HWFRAME_MAP_OVERWRITE
);
273 map
->width
= src
->width
;
274 map
->height
= src
->height
;
276 err
= av_frame_copy(map
, src
);
286 static int drm_map_from(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
287 const AVFrame
*src
, int flags
)
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
);
296 err
= drm_map_frame(hwfc
, dst
, src
, flags
);
300 err
= av_frame_copy_props(dst
, src
);
307 const HWContextType ff_hwcontext_type_drm
= {
308 .type
= AV_HWDEVICE_TYPE_DRM
,
311 .device_hwctx_size
= sizeof(AVDRMDeviceContext
),
313 .device_create
= &drm_device_create
,
315 .frames_get_buffer
= &drm_get_buffer
,
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
,
322 .pix_fmts
= (const enum AVPixelFormat
[]) {
323 AV_PIX_FMT_DRM_PRIME
,