From patchwork Sat Aug 4 00:40:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukas Rusak X-Patchwork-Id: 9881 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:104:0:0:0:0:0 with SMTP id c4-v6csp726298jad; Fri, 3 Aug 2018 17:40:57 -0700 (PDT) X-Google-Smtp-Source: AAOMgpepAfkMq0l1oqS2a/XkV8VCqL0Cp3kT30uCDeV+i/la8KNmJtc0GzGtVR8sAW1cZDJ4+pso X-Received: by 2002:a1c:90e:: with SMTP id 14-v6mr6324607wmj.130.1533343257024; Fri, 03 Aug 2018 17:40:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1533343256; cv=none; d=google.com; s=arc-20160816; b=oFWkbSRh0AAvpHchf1UfVdvOlwOoegFfv5smo6hA6iMYG0T+IBBKW994BcYspOG9O4 A5Rl+t7UnMelVu+79MzCUN02OMR8HOSaKF+u17ei3MlAjamoTOjC+cO6LfDqNlKqbUxP R7I5EqdCHjBVUu1Z4jNBZgQeOWvMmZk7hKgiFfkcbFcPa7ygweCXv37aVFtc+jdtT9i+ /0ejOLmtqjKWykhx4A0oe+It5W0OoMG/HLTE68MHz4FyMWeHlgsPxNSj/671O8SuPOPI G74fGAvdHsZlEttjTTYXCGOiQS+745UCAxlF4T4jjEy34ebD+yAN8IfL9AWjrAbInZUh lwUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=rs/qpzHqfEDht462GmwFpSday2Y8RoCR5XvCi6zLyoI=; b=OByacm6LLhblIJzSKzEDp0mojlnuIS0OkPBm9F2uBo4ll1p+xhmOCwt48Twh9oSG3a EAWr28iN3KEruuX75ysKVfMzJnBEpOpyNToAEsfPbeJmBm4h9WYyFBCuTB00aTi4H026 GM3CGPqJ/4dGKDZrH8zs1Ul198VteLGfOL+Ca5WXXyWsL5OgcOGhlKBeUKl6OUfICuTX bDvw98Tje37nrDLzlHjvOV/ShAl+SdW1DucS8rub+ahuBV4vGo+i+r8+fA0mSptIEPoc 65O1J2Qrk2pIVaLcCoodd8384JPDTiXJd8Nkr99byyW/SiCFwoe3kDgHjhIS37F2DnDT bMxA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=NGk7cB2w; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id l18-v6si455792wme.197.2018.08.03.17.40.56; Fri, 03 Aug 2018 17:40:56 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=NGk7cB2w; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0A9BE689E50; Sat, 4 Aug 2018 03:40:26 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf1-f177.google.com (mail-pf1-f177.google.com [209.85.210.177]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id DF531689A69 for ; Sat, 4 Aug 2018 03:40:18 +0300 (EEST) Received: by mail-pf1-f177.google.com with SMTP id u24-v6so4048092pfn.13 for ; Fri, 03 Aug 2018 17:40:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=FwTvjvOZbiacQV0BprRy3O04VijmzVcB6jnxx92zu6E=; b=NGk7cB2wE6Z9wvYvHF29T/HoSFWWScPIOxwyC4zZ8ygO0MoLKZIamhDNYqOpG16Oq9 A9avfxZfXsiHkv8XxZ4ZqbKITUv2eDiQjw+ITPY4S2u1/xOtByg5Y1YBebcHXdkSd/8y rRLfJBmswrWyjZ6zvsfHMDwxJ+WlAVR/Pvt4DZ8yD4PFXdtA/qYR7+6DDI7ZZSSCbdyI NlUbxX4rJMIgsNJc8gQNxVTKkHvXXmZEgFrQFlHSMPDIQnKMPXZYFkzLYz9k8X2WYRbp M6FhFLKN5ma1dpy+F4s2ADcthJX02YV1GP19MIuQS4yTOHaegCPxhXBcrACeZy5xKD3z 29Kg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=FwTvjvOZbiacQV0BprRy3O04VijmzVcB6jnxx92zu6E=; b=aYu4gXphb2q9pEE7SoMlOr38cgG+WZQTcKXwsKSOs6QRAQUflPsmn5heVO84HFsPp1 ZZ1u60lpjKBmlLlgq5wknmF+/txoRJF0PNlvyKYNQXlFOdyTeVfJ6GniCD5d9LPi/BMo F9pSIHoPT5BcatMSpqGDx9tzmjhtk9mEjTBrfqLlhQXKueazMTO41zZeAlNrg3/EzUaE VHAyTlR2IbpRZrTQ3Z7TnTaexFMYg289V0ab2jQgrwiYoOX58tdD2Qa46GYtgDAf39a5 y27g6aWfPTUV3rAAFwV16Ddk3kvIKeJE8Pq/E6WS3XHSBIhTkz0Gz8BTJGAq6/XEjntq U+eA== X-Gm-Message-State: AOUpUlFdwjy6ezhJBtKBB/e75lc/qQaRNSKqhMBI7VzcgOjtndftvPVG 4kE6t1sjNV3kimYJK06vrDRJmgtZ X-Received: by 2002:a62:da12:: with SMTP id c18-v6mr6865428pfh.50.1533343235417; Fri, 03 Aug 2018 17:40:35 -0700 (PDT) Received: from localhost.localdomain (d154-20-200-72.bchsia.telus.net. [154.20.200.72]) by smtp.gmail.com with ESMTPSA id e8-v6sm1107265pfj.16.2018.08.03.17.40.34 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 Aug 2018 17:40:34 -0700 (PDT) From: Lukas Rusak To: ffmpeg-devel@ffmpeg.org Date: Fri, 3 Aug 2018 17:40:29 -0700 Message-Id: <20180804004031.12143-2-lorusak@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180804004031.12143-1-lorusak@gmail.com> References: <20180804004031.12143-1-lorusak@gmail.com> Subject: [FFmpeg-devel] [PATCH 2/4] libavcodec: v4l2m2m: output AVDRMFrameDescriptor X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This allows for a zero-copy output by exporting the v4l2 buffer then wrapping that buffer in the AVDRMFrameDescriptor like it is done in rkmpp. This has been in use for quite some time with great success on many platforms including: - Amlogic S905 - Raspberry Pi - i.MX6 - Dragonboard 410c This was developed in conjunction with Kodi to allow handling the zero-copy buffer rendering. A simply utility for testing is also available here: https://github.com/BayLibre/ffmpeg-drm todo: - allow selecting pixel format output from decoder - allow configuring amount of output and capture buffers V2: - allow selecting AV_PIX_FMT_DRM_PRIME V3: - use get_format to select AV_PIX_FMT_DRM_PRIME - use hw_configs - add handling of AV_PIX_FMT_YUV420P format (for raspberry pi) - add handling of AV_PIX_FMT_YUYV422 format (for i.MX6 coda decoder) --- libavcodec/v4l2_buffers.c | 216 ++++++++++++++++++++++++++++++++------ libavcodec/v4l2_buffers.h | 4 + libavcodec/v4l2_context.c | 40 ++++++- libavcodec/v4l2_m2m.c | 4 +- libavcodec/v4l2_m2m.h | 3 + libavcodec/v4l2_m2m_dec.c | 23 ++++ 6 files changed, 253 insertions(+), 37 deletions(-) diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c index aef911f3bb..e5c46ac81e 100644 --- a/libavcodec/v4l2_buffers.c +++ b/libavcodec/v4l2_buffers.c @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include @@ -29,6 +30,7 @@ #include #include "libavcodec/avcodec.h" #include "libavcodec/internal.h" +#include "libavutil/hwcontext.h" #include "v4l2_context.h" #include "v4l2_buffers.h" #include "v4l2_m2m.h" @@ -203,7 +205,79 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) return AVCOL_TRC_UNSPECIFIED; } -static void v4l2_free_buffer(void *opaque, uint8_t *unused) +static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf) +{ + AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame; + AVDRMLayerDescriptor *layer; + + /* fill the DRM frame descriptor */ + drm_desc->nb_objects = avbuf->num_planes; + drm_desc->nb_layers = 1; + + layer = &drm_desc->layers[0]; + layer->nb_planes = avbuf->num_planes; + + for (int i = 0; i < avbuf->num_planes; i++) { + layer->planes[i].object_index = i; + layer->planes[i].offset = 0; + layer->planes[i].pitch = avbuf->plane_info[i].bytesperline; + } + + switch (avbuf->context->av_pix_fmt) { + case AV_PIX_FMT_YUYV422: + + layer->format = DRM_FORMAT_YUYV; + layer->nb_planes = 1; + + break; + + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV21: + + layer->format = avbuf->context->av_pix_fmt == AV_PIX_FMT_NV12 ? + DRM_FORMAT_NV12 : DRM_FORMAT_NV21; + + if (avbuf->num_planes > 1) + break; + + layer->nb_planes = 2; + + layer->planes[1].object_index = 0; + layer->planes[1].offset = avbuf->plane_info[0].bytesperline * + avbuf->context->format.fmt.pix.height; + layer->planes[1].pitch = avbuf->plane_info[0].bytesperline; + break; + + case AV_PIX_FMT_YUV420P: + + layer->format = DRM_FORMAT_YUV420; + + if (avbuf->num_planes > 1) + break; + + layer->nb_planes = 3; + + layer->planes[1].object_index = 0; + layer->planes[1].offset = avbuf->plane_info[0].bytesperline * + avbuf->context->format.fmt.pix.height; + layer->planes[1].pitch = avbuf->plane_info[0].bytesperline >> 1; + + layer->planes[2].object_index = 0; + layer->planes[2].offset = layer->planes[1].offset + + ((avbuf->plane_info[0].bytesperline * + avbuf->context->format.fmt.pix.height) >> 2); + layer->planes[2].pitch = avbuf->plane_info[0].bytesperline >> 1; + break; + + default: + drm_desc->nb_layers = 0; + break; + } + + return (uint8_t *) drm_desc; +} + +static void v4l2_free_buffer(void *opaque, uint8_t *data) { V4L2Buffer* avbuf = opaque; V4L2m2mContext *s = buf_to_m2mctx(avbuf); @@ -227,27 +301,47 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) } } -static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) +static int v4l2_buffer_export_drm(V4L2Buffer* avbuf) { - V4L2m2mContext *s = buf_to_m2mctx(in); + struct v4l2_exportbuffer expbuf; + int i, ret; - if (plane >= in->num_planes) - return AVERROR(EINVAL); + for (i = 0; i < avbuf->num_planes; i++) { + memset(&expbuf, 0, sizeof(expbuf)); - /* even though most encoders return 0 in data_offset encoding vp8 does require this value */ - *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset, - in->plane_info[plane].length, v4l2_free_buffer, in, 0); - if (!*buf) - return AVERROR(ENOMEM); + expbuf.index = avbuf->buf.index; + expbuf.type = avbuf->buf.type; + expbuf.plane = i; + + ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_EXPBUF, &expbuf); + if (ret < 0) + return AVERROR(errno); + + if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type)) { + /* drm frame */ + avbuf->drm_frame.objects[i].size = avbuf->buf.m.planes[i].length; + avbuf->drm_frame.objects[i].fd = expbuf.fd; + } else { + /* drm frame */ + avbuf->drm_frame.objects[0].size = avbuf->buf.length; + avbuf->drm_frame.objects[0].fd = expbuf.fd; + } + } + + return 0; +} + +static int v4l2_buf_increase_ref(V4L2Buffer *in) +{ + V4L2m2mContext *s = buf_to_m2mctx(in); if (in->context_ref) atomic_fetch_add(&in->context_refcount, 1); else { in->context_ref = av_buffer_ref(s->self_ref); - if (!in->context_ref) { - av_buffer_unref(buf); + if (!in->context_ref) return AVERROR(ENOMEM); - } + in->context_refcount = 1; } @@ -257,6 +351,46 @@ static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) return 0; } +static int v4l2_buf_to_bufref_drm(V4L2Buffer *in, AVBufferRef **buf) +{ + int ret; + + *buf = av_buffer_create((uint8_t *) &in->drm_frame, + sizeof(in->drm_frame), + v4l2_free_buffer, + in, AV_BUFFER_FLAG_READONLY); + if (!*buf) + return AVERROR(ENOMEM); + + ret = v4l2_buf_increase_ref(in); + if (ret) + av_buffer_unref(buf); + + return ret; +} + +static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) +{ + int ret; + + if (plane >= in->num_planes) + return AVERROR(EINVAL); + + /* most encoders return 0 in data_offset but vp8 does require this value */ + *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset, + in->plane_info[plane].length, + v4l2_free_buffer, + in, 0); + if (!*buf) + return AVERROR(ENOMEM); + + ret = v4l2_buf_increase_ref(in); + if (ret) + av_buffer_unref(buf); + + return ret; +} + static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, AVBufferRef* bref) { unsigned int bytesused, length; @@ -308,31 +442,43 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) av_frame_unref(frame); - /* 1. get references to the actual data */ - for (i = 0; i < avbuf->num_planes; i++) { - ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]); + if (buf_to_m2mctx(avbuf)->output_drm) { + /* 1. get references to the actual data */ + ret = v4l2_buf_to_bufref_drm(avbuf, &frame->buf[0]); if (ret) return ret; - frame->linesize[i] = avbuf->plane_info[i].bytesperline; - frame->data[i] = frame->buf[i]->data; - } + frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf); + frame->format = AV_PIX_FMT_DRM_PRIME; + } else { + /* 1. get references to the actual data */ + for (i = 0; i < avbuf->num_planes; i++) { + ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]); + if (ret) + return ret; + + frame->linesize[i] = avbuf->plane_info[i].bytesperline; + frame->data[i] = frame->buf[i]->data; + } - /* 1.1 fixup special cases */ - switch (avbuf->context->av_pix_fmt) { - case AV_PIX_FMT_NV12: - if (avbuf->num_planes > 1) + /* 1.1 fixup special cases */ + switch (avbuf->context->av_pix_fmt) { + case AV_PIX_FMT_NV12: + if (avbuf->num_planes > 1) + break; + frame->linesize[1] = avbuf->plane_info[0].bytesperline; + frame->data[1] = frame->buf[0]->data + + avbuf->plane_info[0].bytesperline * + avbuf->context->format.fmt.pix.height; break; - frame->linesize[1] = avbuf->plane_info[0].bytesperline; - frame->data[1] = frame->buf[0]->data + avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height; - break; - default: - break; + default: + break; + } + frame->format = avbuf->context->av_pix_fmt; } /* 2. get frame information */ frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME); - frame->format = avbuf->context->av_pix_fmt; frame->color_primaries = v4l2_get_color_primaries(avbuf); frame->colorspace = v4l2_get_color_space(avbuf); frame->color_range = v4l2_get_color_range(avbuf); @@ -447,9 +593,6 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) avbuf->status = V4L2BUF_AVAILABLE; - if (V4L2_TYPE_IS_OUTPUT(ctx->type)) - return 0; - if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { avbuf->buf.m.planes = avbuf->planes; avbuf->buf.length = avbuf->num_planes; @@ -459,6 +602,15 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) avbuf->buf.length = avbuf->planes[0].length; } + if (V4L2_TYPE_IS_OUTPUT(ctx->type)) + return 0; + + if (buf_to_m2mctx(avbuf)->output_drm) { + ret = v4l2_buffer_export_drm(avbuf); + if (ret) + return ret; + } + return ff_v4l2_buffer_enqueue(avbuf); } diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h index dc5cc9e267..a8a50ecc65 100644 --- a/libavcodec/v4l2_buffers.h +++ b/libavcodec/v4l2_buffers.h @@ -27,6 +27,7 @@ #include #include +#include "libavutil/hwcontext_drm.h" #include "avcodec.h" enum V4L2Buffer_status { @@ -42,6 +43,9 @@ typedef struct V4L2Buffer { /* each buffer needs to have a reference to its context */ struct V4L2Context *context; + /* DRM descriptor */ + AVDRMFrameDescriptor drm_frame; + /* This object is refcounted per-plane, so we need to keep track * of how many context-refs we are holding. */ AVBufferRef *context_ref; diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index efcb0426e4..9457fadb1e 100644 --- a/libavcodec/v4l2_context.c +++ b/libavcodec/v4l2_context.c @@ -393,22 +393,54 @@ static int v4l2_release_buffers(V4L2Context* ctx) struct v4l2_requestbuffers req = { .memory = V4L2_MEMORY_MMAP, .type = ctx->type, - .count = 0, /* 0 -> unmaps buffers from the driver */ + .count = 0, /* 0 -> unmap all buffers from the driver */ }; - int i, j; + int ret, i, j; for (i = 0; i < ctx->num_buffers; i++) { V4L2Buffer *buffer = &ctx->buffers[i]; for (j = 0; j < buffer->num_planes; j++) { struct V4L2Plane_info *p = &buffer->plane_info[j]; + + if (V4L2_TYPE_IS_OUTPUT(ctx->type)) { + /* output buffers are not EXPORTED */ + goto unmap; + } + + if (ctx_to_m2mctx(ctx)->output_drm) { + /* use the DRM frame to close */ + if (buffer->drm_frame.objects[j].fd >= 0) { + if (close(buffer->drm_frame.objects[j].fd) < 0) { + av_log(logger(ctx), AV_LOG_ERROR, "%s close drm fd " + "[buffer=%2d, plane=%d, fd=%2d] - %s \n", + ctx->name, i, j, buffer->drm_frame.objects[j].fd, + av_err2str(AVERROR(errno))); + } + } + } +unmap: if (p->mm_addr && p->length) if (munmap(p->mm_addr, p->length) < 0) - av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ctx->name, av_err2str(AVERROR(errno))); + av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", + ctx->name, av_err2str(AVERROR(errno))); } } - return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req); + ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req); + if (ret < 0) { + av_log(logger(ctx), AV_LOG_ERROR, "release all %s buffers (%s)\n", + ctx->name, av_err2str(AVERROR(errno))); + + if (ctx_to_m2mctx(ctx)->output_drm) + av_log(logger(ctx), AV_LOG_ERROR, + "Make sure the DRM client releases all FB/GEM objects before closing the codec (ie):\n" + "for all buffers: \n" + " 1. drmModeRmFB(..)\n" + " 2. drmIoctl(.., DRM_IOCTL_GEM_CLOSE,... )\n"); + } + + return ret; } static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt) diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c index 427e165f58..7896326e80 100644 --- a/libavcodec/v4l2_m2m.c +++ b/libavcodec/v4l2_m2m.c @@ -159,7 +159,9 @@ static int v4l2_configure_contexts(V4L2m2mContext* s) goto error; } - /* decoder's buffers need to be updated at a later stage */ + /* decoder's capture buffers are updated during v4l2_try_start once we find + * the valid format. + */ if (!av_codec_is_decoder(s->avctx->codec)) { ret = ff_v4l2_context_init(&s->capture); if (ret) { diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h index 452bf0d9bc..9ac5a2448d 100644 --- a/libavcodec/v4l2_m2m.h +++ b/libavcodec/v4l2_m2m.h @@ -59,6 +59,9 @@ typedef struct V4L2m2mContext { /* Reference to self; only valid while codec is active. */ AVBufferRef *self_ref; + + /* generate DRM frames */ + int output_drm; } V4L2m2mContext; typedef struct V4L2m2mPriv diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c index 7926e25efa..29d894492f 100644 --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c @@ -23,12 +23,18 @@ #include #include + +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_drm.h" #include "libavutil/pixfmt.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "libavcodec/avcodec.h" #include "libavcodec/decode.h" +#include "libavcodec/hwaccel.h" +#include "libavcodec/internal.h" + #include "v4l2_context.h" #include "v4l2_m2m.h" #include "v4l2_fmt.h" @@ -186,6 +192,15 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) capture->av_codec_id = AV_CODEC_ID_RAWVIDEO; capture->av_pix_fmt = avctx->pix_fmt; + /* the client requests the codec to generate DRM frames: + * - data[0] will therefore point to the returned AVDRMFrameDescriptor + * check the ff_v4l2_buffer_to_avframe conversion function. + * - the DRM frame format is passed in the DRM frame descriptor layer. + * check the v4l2_get_drm_frame function. + */ + if (ff_get_format(avctx, avctx->codec->pix_fmts) == AV_PIX_FMT_DRM_PRIME) + s->output_drm = 1; + ret = ff_v4l2_m2m_codec_init(avctx); if (ret) { av_log(avctx, AV_LOG_ERROR, "can't configure decoder\n"); @@ -205,6 +220,11 @@ static const AVOption options[] = { { NULL}, }; +static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = { + HW_CONFIG_INTERNAL(DRM_PRIME), + NULL +}; + #define M2MDEC_CLASS(NAME) \ static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \ .class_name = #NAME "_v4l2_m2m_decoder", \ @@ -225,7 +245,10 @@ static const AVOption options[] = { .init = v4l2_decode_init, \ .receive_frame = v4l2_receive_frame, \ .close = ff_v4l2_m2m_codec_end, \ + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ + AV_PIX_FMT_NONE}, \ .bsfs = bsf_name, \ + .hw_configs = v4l2_m2m_hw_configs, \ .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ AV_CODEC_CAP_AVOID_PROBING, \ .wrapper_name = "v4l2m2m", \