1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci#include "config.h" 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci#include <fcntl.h> 22cabdff1aSopenharmony_ci#include <sys/mman.h> 23cabdff1aSopenharmony_ci#include <unistd.h> 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci/* This was introduced in version 4.6. And may not exist all without an 26cabdff1aSopenharmony_ci * optional package. So to prevent a hard dependency on needing the Linux 27cabdff1aSopenharmony_ci * kernel headers to compile, make this optional. */ 28cabdff1aSopenharmony_ci#if HAVE_LINUX_DMA_BUF_H 29cabdff1aSopenharmony_ci#include <linux/dma-buf.h> 30cabdff1aSopenharmony_ci#include <sys/ioctl.h> 31cabdff1aSopenharmony_ci#endif 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#include <drm.h> 34cabdff1aSopenharmony_ci#include <xf86drm.h> 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_ci#include "avassert.h" 37cabdff1aSopenharmony_ci#include "hwcontext.h" 38cabdff1aSopenharmony_ci#include "hwcontext_drm.h" 39cabdff1aSopenharmony_ci#include "hwcontext_internal.h" 40cabdff1aSopenharmony_ci#include "imgutils.h" 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_cistatic void drm_device_free(AVHWDeviceContext *hwdev) 44cabdff1aSopenharmony_ci{ 45cabdff1aSopenharmony_ci AVDRMDeviceContext *hwctx = hwdev->hwctx; 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci close(hwctx->fd); 48cabdff1aSopenharmony_ci} 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_cistatic int drm_device_create(AVHWDeviceContext *hwdev, const char *device, 51cabdff1aSopenharmony_ci AVDictionary *opts, int flags) 52cabdff1aSopenharmony_ci{ 53cabdff1aSopenharmony_ci AVDRMDeviceContext *hwctx = hwdev->hwctx; 54cabdff1aSopenharmony_ci drmVersionPtr version; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci hwctx->fd = open(device, O_RDWR); 57cabdff1aSopenharmony_ci if (hwctx->fd < 0) 58cabdff1aSopenharmony_ci return AVERROR(errno); 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci version = drmGetVersion(hwctx->fd); 61cabdff1aSopenharmony_ci if (!version) { 62cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_ERROR, "Failed to get version information " 63cabdff1aSopenharmony_ci "from %s: probably not a DRM device?\n", device); 64cabdff1aSopenharmony_ci close(hwctx->fd); 65cabdff1aSopenharmony_ci return AVERROR(EINVAL); 66cabdff1aSopenharmony_ci } 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_VERBOSE, "Opened DRM device %s: driver %s " 69cabdff1aSopenharmony_ci "version %d.%d.%d.\n", device, version->name, 70cabdff1aSopenharmony_ci version->version_major, version->version_minor, 71cabdff1aSopenharmony_ci version->version_patchlevel); 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_ci drmFreeVersion(version); 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_ci hwdev->free = &drm_device_free; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci return 0; 78cabdff1aSopenharmony_ci} 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_cistatic int drm_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) 81cabdff1aSopenharmony_ci{ 82cabdff1aSopenharmony_ci frame->buf[0] = av_buffer_pool_get(hwfc->pool); 83cabdff1aSopenharmony_ci if (!frame->buf[0]) 84cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_ci frame->data[0] = (uint8_t*)frame->buf[0]->data; 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci frame->format = AV_PIX_FMT_DRM_PRIME; 89cabdff1aSopenharmony_ci frame->width = hwfc->width; 90cabdff1aSopenharmony_ci frame->height = hwfc->height; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci return 0; 93cabdff1aSopenharmony_ci} 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_citypedef struct DRMMapping { 96cabdff1aSopenharmony_ci // Address and length of each mmap()ed region. 97cabdff1aSopenharmony_ci int nb_regions; 98cabdff1aSopenharmony_ci int sync_flags; 99cabdff1aSopenharmony_ci int object[AV_DRM_MAX_PLANES]; 100cabdff1aSopenharmony_ci void *address[AV_DRM_MAX_PLANES]; 101cabdff1aSopenharmony_ci size_t length[AV_DRM_MAX_PLANES]; 102cabdff1aSopenharmony_ci} DRMMapping; 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_cistatic void drm_unmap_frame(AVHWFramesContext *hwfc, 105cabdff1aSopenharmony_ci HWMapDescriptor *hwmap) 106cabdff1aSopenharmony_ci{ 107cabdff1aSopenharmony_ci DRMMapping *map = hwmap->priv; 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci for (int i = 0; i < map->nb_regions; i++) { 110cabdff1aSopenharmony_ci#if HAVE_LINUX_DMA_BUF_H 111cabdff1aSopenharmony_ci struct dma_buf_sync sync = { .flags = DMA_BUF_SYNC_END | map->sync_flags }; 112cabdff1aSopenharmony_ci ioctl(map->object[i], DMA_BUF_IOCTL_SYNC, &sync); 113cabdff1aSopenharmony_ci#endif 114cabdff1aSopenharmony_ci munmap(map->address[i], map->length[i]); 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci av_free(map); 118cabdff1aSopenharmony_ci} 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_cistatic int drm_map_frame(AVHWFramesContext *hwfc, 121cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src, int flags) 122cabdff1aSopenharmony_ci{ 123cabdff1aSopenharmony_ci const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)src->data[0]; 124cabdff1aSopenharmony_ci#if HAVE_LINUX_DMA_BUF_H 125cabdff1aSopenharmony_ci struct dma_buf_sync sync_start = { 0 }; 126cabdff1aSopenharmony_ci#endif 127cabdff1aSopenharmony_ci DRMMapping *map; 128cabdff1aSopenharmony_ci int err, i, p, plane; 129cabdff1aSopenharmony_ci int mmap_prot; 130cabdff1aSopenharmony_ci void *addr; 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci map = av_mallocz(sizeof(*map)); 133cabdff1aSopenharmony_ci if (!map) 134cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_ci mmap_prot = 0; 137cabdff1aSopenharmony_ci if (flags & AV_HWFRAME_MAP_READ) 138cabdff1aSopenharmony_ci mmap_prot |= PROT_READ; 139cabdff1aSopenharmony_ci if (flags & AV_HWFRAME_MAP_WRITE) 140cabdff1aSopenharmony_ci mmap_prot |= PROT_WRITE; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci#if HAVE_LINUX_DMA_BUF_H 143cabdff1aSopenharmony_ci if (flags & AV_HWFRAME_MAP_READ) 144cabdff1aSopenharmony_ci map->sync_flags |= DMA_BUF_SYNC_READ; 145cabdff1aSopenharmony_ci if (flags & AV_HWFRAME_MAP_WRITE) 146cabdff1aSopenharmony_ci map->sync_flags |= DMA_BUF_SYNC_WRITE; 147cabdff1aSopenharmony_ci sync_start.flags = DMA_BUF_SYNC_START | map->sync_flags; 148cabdff1aSopenharmony_ci#endif 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci av_assert0(desc->nb_objects <= AV_DRM_MAX_PLANES); 151cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_objects; i++) { 152cabdff1aSopenharmony_ci addr = mmap(NULL, desc->objects[i].size, mmap_prot, MAP_SHARED, 153cabdff1aSopenharmony_ci desc->objects[i].fd, 0); 154cabdff1aSopenharmony_ci if (addr == MAP_FAILED) { 155cabdff1aSopenharmony_ci err = AVERROR(errno); 156cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to map DRM object %d to " 157cabdff1aSopenharmony_ci "memory: %d.\n", desc->objects[i].fd, errno); 158cabdff1aSopenharmony_ci goto fail; 159cabdff1aSopenharmony_ci } 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci map->address[i] = addr; 162cabdff1aSopenharmony_ci map->length[i] = desc->objects[i].size; 163cabdff1aSopenharmony_ci map->object[i] = desc->objects[i].fd; 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci#if HAVE_LINUX_DMA_BUF_H 166cabdff1aSopenharmony_ci /* We're not checking for errors here because the kernel may not 167cabdff1aSopenharmony_ci * support the ioctl, in which case its okay to carry on */ 168cabdff1aSopenharmony_ci ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_SYNC, &sync_start); 169cabdff1aSopenharmony_ci#endif 170cabdff1aSopenharmony_ci } 171cabdff1aSopenharmony_ci map->nb_regions = i; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci plane = 0; 174cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_layers; i++) { 175cabdff1aSopenharmony_ci const AVDRMLayerDescriptor *layer = &desc->layers[i]; 176cabdff1aSopenharmony_ci for (p = 0; p < layer->nb_planes; p++) { 177cabdff1aSopenharmony_ci dst->data[plane] = 178cabdff1aSopenharmony_ci (uint8_t*)map->address[layer->planes[p].object_index] + 179cabdff1aSopenharmony_ci layer->planes[p].offset; 180cabdff1aSopenharmony_ci dst->linesize[plane] = layer->planes[p].pitch; 181cabdff1aSopenharmony_ci ++plane; 182cabdff1aSopenharmony_ci } 183cabdff1aSopenharmony_ci } 184cabdff1aSopenharmony_ci av_assert0(plane <= AV_DRM_MAX_PLANES); 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci dst->width = src->width; 187cabdff1aSopenharmony_ci dst->height = src->height; 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, 190cabdff1aSopenharmony_ci &drm_unmap_frame, map); 191cabdff1aSopenharmony_ci if (err < 0) 192cabdff1aSopenharmony_ci goto fail; 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ci return 0; 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_cifail: 197cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_objects; i++) { 198cabdff1aSopenharmony_ci if (map->address[i]) 199cabdff1aSopenharmony_ci munmap(map->address[i], map->length[i]); 200cabdff1aSopenharmony_ci } 201cabdff1aSopenharmony_ci av_free(map); 202cabdff1aSopenharmony_ci return err; 203cabdff1aSopenharmony_ci} 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_cistatic int drm_transfer_get_formats(AVHWFramesContext *ctx, 206cabdff1aSopenharmony_ci enum AVHWFrameTransferDirection dir, 207cabdff1aSopenharmony_ci enum AVPixelFormat **formats) 208cabdff1aSopenharmony_ci{ 209cabdff1aSopenharmony_ci enum AVPixelFormat *pix_fmts; 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci pix_fmts = av_malloc_array(2, sizeof(*pix_fmts)); 212cabdff1aSopenharmony_ci if (!pix_fmts) 213cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 214cabdff1aSopenharmony_ci 215cabdff1aSopenharmony_ci pix_fmts[0] = ctx->sw_format; 216cabdff1aSopenharmony_ci pix_fmts[1] = AV_PIX_FMT_NONE; 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_ci *formats = pix_fmts; 219cabdff1aSopenharmony_ci return 0; 220cabdff1aSopenharmony_ci} 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_cistatic int drm_transfer_data_from(AVHWFramesContext *hwfc, 223cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src) 224cabdff1aSopenharmony_ci{ 225cabdff1aSopenharmony_ci AVFrame *map; 226cabdff1aSopenharmony_ci int err; 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci if (dst->width > hwfc->width || dst->height > hwfc->height) 229cabdff1aSopenharmony_ci return AVERROR(EINVAL); 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci map = av_frame_alloc(); 232cabdff1aSopenharmony_ci if (!map) 233cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 234cabdff1aSopenharmony_ci map->format = dst->format; 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci err = drm_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ); 237cabdff1aSopenharmony_ci if (err) 238cabdff1aSopenharmony_ci goto fail; 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ci map->width = dst->width; 241cabdff1aSopenharmony_ci map->height = dst->height; 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci err = av_frame_copy(dst, map); 244cabdff1aSopenharmony_ci if (err) 245cabdff1aSopenharmony_ci goto fail; 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci err = 0; 248cabdff1aSopenharmony_cifail: 249cabdff1aSopenharmony_ci av_frame_free(&map); 250cabdff1aSopenharmony_ci return err; 251cabdff1aSopenharmony_ci} 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_cistatic int drm_transfer_data_to(AVHWFramesContext *hwfc, 254cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src) 255cabdff1aSopenharmony_ci{ 256cabdff1aSopenharmony_ci AVFrame *map; 257cabdff1aSopenharmony_ci int err; 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci if (src->width > hwfc->width || src->height > hwfc->height) 260cabdff1aSopenharmony_ci return AVERROR(EINVAL); 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci map = av_frame_alloc(); 263cabdff1aSopenharmony_ci if (!map) 264cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 265cabdff1aSopenharmony_ci map->format = src->format; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci err = drm_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | 268cabdff1aSopenharmony_ci AV_HWFRAME_MAP_OVERWRITE); 269cabdff1aSopenharmony_ci if (err) 270cabdff1aSopenharmony_ci goto fail; 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci map->width = src->width; 273cabdff1aSopenharmony_ci map->height = src->height; 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci err = av_frame_copy(map, src); 276cabdff1aSopenharmony_ci if (err) 277cabdff1aSopenharmony_ci goto fail; 278cabdff1aSopenharmony_ci 279cabdff1aSopenharmony_ci err = 0; 280cabdff1aSopenharmony_cifail: 281cabdff1aSopenharmony_ci av_frame_free(&map); 282cabdff1aSopenharmony_ci return err; 283cabdff1aSopenharmony_ci} 284cabdff1aSopenharmony_ci 285cabdff1aSopenharmony_cistatic int drm_map_from(AVHWFramesContext *hwfc, AVFrame *dst, 286cabdff1aSopenharmony_ci const AVFrame *src, int flags) 287cabdff1aSopenharmony_ci{ 288cabdff1aSopenharmony_ci int err; 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci if (hwfc->sw_format != dst->format) 291cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci err = drm_map_frame(hwfc, dst, src, flags); 294cabdff1aSopenharmony_ci if (err) 295cabdff1aSopenharmony_ci return err; 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ci err = av_frame_copy_props(dst, src); 298cabdff1aSopenharmony_ci if (err) 299cabdff1aSopenharmony_ci return err; 300cabdff1aSopenharmony_ci 301cabdff1aSopenharmony_ci return 0; 302cabdff1aSopenharmony_ci} 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_ciconst HWContextType ff_hwcontext_type_drm = { 305cabdff1aSopenharmony_ci .type = AV_HWDEVICE_TYPE_DRM, 306cabdff1aSopenharmony_ci .name = "DRM", 307cabdff1aSopenharmony_ci 308cabdff1aSopenharmony_ci .device_hwctx_size = sizeof(AVDRMDeviceContext), 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci .device_create = &drm_device_create, 311cabdff1aSopenharmony_ci 312cabdff1aSopenharmony_ci .frames_get_buffer = &drm_get_buffer, 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci .transfer_get_formats = &drm_transfer_get_formats, 315cabdff1aSopenharmony_ci .transfer_data_to = &drm_transfer_data_to, 316cabdff1aSopenharmony_ci .transfer_data_from = &drm_transfer_data_from, 317cabdff1aSopenharmony_ci .map_from = &drm_map_from, 318cabdff1aSopenharmony_ci 319cabdff1aSopenharmony_ci .pix_fmts = (const enum AVPixelFormat[]) { 320cabdff1aSopenharmony_ci AV_PIX_FMT_DRM_PRIME, 321cabdff1aSopenharmony_ci AV_PIX_FMT_NONE 322cabdff1aSopenharmony_ci }, 323cabdff1aSopenharmony_ci}; 324