1From daa0a3edba13cf3415c1dbb6c765667206e55861 Mon Sep 17 00:00:00 2001 2From: Jeffy Chen <jeffy.chen@rock-chips.com> 3Date: Mon, 20 Jan 2020 18:33:20 +0800 4Subject: [PATCH 2/4] HACK: vo_xv: Support dma buffer rendering 5 6Send dma buffer to xv port when it supports dma port attributes. 7 8Depends on: 91/ ffmpeg with hw format AV_PIX_FMT_DRM_PRIME and sw format 10AV_PIX_FMT_NV12. 11 122/ xserver xv with NV12 dma buf rendering hacks. 13 14Tested with: 15mpv --hwdec=rkmpp --vd-lavc-software-fallback=no --vo=xv test.mp4 16 17Change-Id: I446cb3061e745b7ef1d5496c228062050ce07064 18Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 19--- 20 video/out/vo_xv.c | 194 +++++++++++++++++++++++++++++++++++++++++++++- 21 1 file changed, 193 insertions(+), 1 deletion(-) 22 23diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c 24index f37a8d1228..1e7211dee4 100644 25--- a/video/out/vo_xv.c 26+++ b/video/out/vo_xv.c 27@@ -23,10 +23,15 @@ 28 #include <stdint.h> 29 #include <stdbool.h> 30 #include <errno.h> 31+#include <unistd.h> 32+#include <sys/socket.h> 33+#include <sys/un.h> 34 #include <X11/Xlib.h> 35 #include <X11/Xutil.h> 36 37 #include <libavutil/common.h> 38+#include <libavutil/hwcontext.h> 39+#include <libavutil/hwcontext_drm.h> 40 41 #include "config.h" 42 43@@ -62,6 +67,18 @@ 44 45 #define MAX_BUFFERS 10 46 47+#define XV_DMA_CLIENT_PROP "XV_DMA_CLIENT_ID" 48+#define XV_DMA_VER_STRIDE_PROP "XV_DMA_VER_STRIDE" 49+#define XV_DMA_HOR_STRIDE_PROP "XV_DMA_HOR_STRIDE" 50+#define XV_DMA_CLIENT_PATH "/tmp/.xv_dma_client" 51+ 52+struct dma_desc { 53+ int hor_stride; 54+ int ver_stride; 55+ int dma_fd; 56+ int valid; 57+}; 58+ 59 struct xvctx { 60 struct xv_ck_info_s { 61 int method; // CK_METHOD_* constants 62@@ -79,6 +96,8 @@ struct xvctx { 63 int current_ip_buf; 64 int num_buffers; 65 XvImage *xvimage[MAX_BUFFERS]; 66+ struct dma_desc dma_descs[MAX_BUFFERS]; 67+ int dma_client_id; 68 struct mp_image *original_image; 69 uint32_t image_width; 70 uint32_t image_height; 71@@ -111,6 +130,7 @@ static const struct fmt_entry fmt_table[] = { 72 {IMGFMT_420P, MP_FOURCC_I420}, 73 {IMGFMT_UYVY, MP_FOURCC_UYVY}, 74 {IMGFMT_NV12, MP_FOURCC_NV12}, 75+ {IMGFMT_DRMPRIME, MP_FOURCC_NV12}, 76 {0} 77 }; 78 79@@ -177,6 +197,144 @@ static int xv_find_atom(struct vo *vo, uint32_t xv_port, const char *name, 80 return atom; 81 } 82 83+static int xv_check_dma_client(struct vo *vo) 84+{ 85+ struct xvctx *ctx = vo->priv; 86+ Atom atom; 87+ int xv_value = 0; 88+ 89+ if (!ctx->dma_client_id) 90+ return -1; 91+ 92+ atom = XInternAtom(vo->x11->display, XV_DMA_CLIENT_PROP, True); 93+ if (atom != None) 94+ XvGetPortAttribute(vo->x11->display, ctx->xv_port, atom, &xv_value); 95+ 96+ if (xv_value) 97+ return 0; 98+ 99+ ctx->dma_client_id = 0; 100+ return -1; 101+} 102+ 103+static void xv_flush_dma_client(struct vo *vo) 104+{ 105+ struct xvctx *ctx = vo->priv; 106+ Atom atom; 107+ 108+ if (!ctx->dma_client_id) 109+ return; 110+ 111+ atom = XInternAtom(vo->x11->display, XV_DMA_CLIENT_PROP, True); 112+ if (atom != None) { 113+ XvSetPortAttribute(vo->x11->display, ctx->xv_port, 114+ atom, ctx->dma_client_id); 115+ XvGetPortAttribute(vo->x11->display, ctx->xv_port, atom, 116+ &ctx->dma_client_id); 117+ } 118+} 119+ 120+static void xv_disable_dma_client(struct vo *vo) 121+{ 122+ struct xvctx *ctx = vo->priv; 123+ Atom atom; 124+ 125+ if (!ctx->dma_client_id) 126+ return; 127+ 128+ atom = XInternAtom(vo->x11->display, XV_DMA_CLIENT_PROP, True); 129+ if (atom != None) 130+ XvSetPortAttribute(vo->x11->display, ctx->xv_port, atom, 0); 131+ 132+ ctx->dma_client_id = 0; 133+} 134+ 135+static void xv_send_dma_params(struct vo *vo, int hor_stride, int ver_stride) 136+{ 137+ struct xvctx *ctx = vo->priv; 138+ Atom atom; 139+ 140+ if (!ctx->dma_client_id) 141+ return; 142+ 143+ atom = XInternAtom(vo->x11->display, XV_DMA_HOR_STRIDE_PROP, True); 144+ if (atom == None) 145+ goto failed; 146+ 147+ XvSetPortAttribute(vo->x11->display, ctx->xv_port, atom, hor_stride); 148+ 149+ atom = XInternAtom(vo->x11->display, XV_DMA_VER_STRIDE_PROP, True); 150+ if (atom == None) 151+ goto failed; 152+ 153+ XvSetPortAttribute(vo->x11->display, ctx->xv_port, atom, ver_stride); 154+ 155+ return; 156+ 157+failed: 158+ xv_disable_dma_client(vo); 159+ ctx->dma_client_id = 0; 160+} 161+ 162+static void xv_send_dma_fd(struct vo *vo, int dma_fd) 163+{ 164+ struct xvctx *ctx = vo->priv; 165+ struct sockaddr_un addr; 166+ struct iovec iov; 167+ struct msghdr msg; 168+ struct cmsghdr *header; 169+ char buf[CMSG_SPACE(sizeof(int))]; 170+ int socket_fd; 171+ 172+ if (!ctx->dma_client_id) 173+ return; 174+ 175+ xv_flush_dma_client(vo); 176+ 177+ socket_fd = socket(PF_UNIX, SOCK_DGRAM, 0); 178+ if (socket_fd < 0) 179+ goto failed; 180+ 181+ addr.sun_family = AF_LOCAL; 182+ snprintf(addr.sun_path, sizeof (addr.sun_path), 183+ XV_DMA_CLIENT_PATH ".%d", ctx->dma_client_id); 184+ addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; 185+ 186+ if (connect(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 187+ goto failed; 188+ 189+ iov.iov_base = buf; 190+ iov.iov_len = 1; 191+ 192+ msg.msg_iov = &iov; 193+ msg.msg_iovlen = 1; 194+ msg.msg_control = buf; 195+ msg.msg_controllen = sizeof(buf); 196+ msg.msg_name = NULL; 197+ msg.msg_namelen = 0; 198+ 199+ header = CMSG_FIRSTHDR(&msg); 200+ header->cmsg_level = SOL_SOCKET; 201+ header->cmsg_type = SCM_RIGHTS; 202+ 203+ header->cmsg_len = CMSG_LEN(sizeof(int)); 204+ *((int *)CMSG_DATA(header)) = dma_fd; 205+ sendmsg(socket_fd, &msg, 0); 206+ 207+ /* Send am empty msg at the end */ 208+ header->cmsg_len = CMSG_LEN(0); 209+ sendmsg(socket_fd, &msg, 0); 210+ 211+ close(socket_fd); 212+ return; 213+ 214+failed: 215+ xv_disable_dma_client(vo); 216+ 217+ if (socket_fd >= 0) 218+ close(socket_fd); 219+} 220+ 221 static int xv_set_eq(struct vo *vo, uint32_t xv_port, const char *name, 222 int value) 223 { 224@@ -508,8 +666,10 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) 225 MP_VERBOSE(vo, "using Xvideo port %d for hw scaling\n", ctx->xv_port); 226 227 // In case config has been called before 228- for (i = 0; i < ctx->num_buffers; i++) 229+ for (i = 0; i < ctx->num_buffers; i++) { 230 deallocate_xvimage(vo, i); 231+ ctx->dma_descs[i].valid = 0; 232+ } 233 234 ctx->num_buffers = ctx->cfg_buffers; 235 236@@ -683,6 +843,14 @@ static void wait_for_completion(struct vo *vo, int max_outstanding) 237 static void flip_page(struct vo *vo) 238 { 239 struct xvctx *ctx = vo->priv; 240+ struct dma_desc *dma_desc = &ctx->dma_descs[ctx->current_buf]; 241+ 242+ if (dma_desc->valid) { 243+ xv_send_dma_fd(vo, dma_desc->dma_fd); 244+ xv_send_dma_params(vo, dma_desc->hor_stride, dma_desc->ver_stride); 245+ dma_desc->valid = 0; 246+ } 247+ 248 put_xvimage(vo, ctx->xvimage[ctx->current_buf]); 249 250 /* remember the currently visible buffer */ 251@@ -701,6 +869,26 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) 252 253 struct mp_image xv_buffer = get_xv_buffer(vo, ctx->current_buf); 254 if (mpi) { 255+ if (mpi->hwctx && !xv_check_dma_client(vo)) { 256+ AVHWFramesContext *fctx = (void *)mpi->hwctx->data; 257+ if (fctx->format == AV_PIX_FMT_DRM_PRIME && 258+ fctx->sw_format == AV_PIX_FMT_NV12) { 259+ AVDRMFrameDescriptor *desc = 260+ (AVDRMFrameDescriptor *)mpi->planes[0]; 261+ AVDRMLayerDescriptor *layer = &desc->layers[0]; 262+ struct dma_desc *dma_desc = &ctx->dma_descs[ctx->current_buf]; 263+ 264+ dma_desc->hor_stride = layer->planes[0].pitch; 265+ dma_desc->ver_stride = 266+ layer->planes[1].offset / dma_desc->hor_stride; 267+ dma_desc->dma_fd = desc->objects[0].fd; 268+ dma_desc->valid = 1; 269+ 270+ // TODO: Draw osd on mmapped hw frame 271+ goto out; 272+ } 273+ } 274+ 275 mp_image_copy(&xv_buffer, mpi); 276 } else { 277 mp_image_clear(&xv_buffer, 0, 0, xv_buffer.w, xv_buffer.h); 278@@ -709,6 +897,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) 279 struct mp_osd_res res = osd_res_from_image_params(vo->params); 280 osd_draw_on_image(vo->osd, res, mpi ? mpi->pts : 0, 0, &xv_buffer); 281 282+out: 283 if (mpi != ctx->original_image) { 284 talloc_free(ctx->original_image); 285 ctx->original_image = mpi; 286@@ -847,6 +1036,9 @@ static int preinit(struct vo *vo) 287 ctx->fo = XvListImageFormats(x11->display, ctx->xv_port, 288 (int *) &ctx->formats); 289 290+ ctx->dma_client_id = getpid(); 291+ xv_flush_dma_client(vo); 292+ 293 MP_WARN(vo, "Warning: this legacy VO has bad quality and performance, " 294 "and will in particular result in blurry OSD and subtitles. " 295 "You should fix your graphics drivers, or not force the xv VO.\n"); 296-- 2972.17.1 298 299