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