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