From daa0a3edba13cf3415c1dbb6c765667206e55861 Mon Sep 17 00:00:00 2001
|
From: Jeffy Chen <jeffy.chen@rock-chips.com>
|
Date: Mon, 20 Jan 2020 18:33:20 +0800
|
Subject: [PATCH 2/4] HACK: vo_xv: Support dma buffer rendering
|
|
Send dma buffer to xv port when it supports dma port attributes.
|
|
Depends on:
|
1/ ffmpeg with hw format AV_PIX_FMT_DRM_PRIME and sw format
|
AV_PIX_FMT_NV12.
|
|
2/ xserver xv with NV12 dma buf rendering hacks.
|
|
Tested with:
|
mpv --hwdec=rkmpp --vd-lavc-software-fallback=no --vo=xv test.mp4
|
|
Change-Id: I446cb3061e745b7ef1d5496c228062050ce07064
|
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
|
---
|
video/out/vo_xv.c | 194 +++++++++++++++++++++++++++++++++++++++++++++-
|
1 file changed, 193 insertions(+), 1 deletion(-)
|
|
diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c
|
index f37a8d1228..1e7211dee4 100644
|
--- a/video/out/vo_xv.c
|
+++ b/video/out/vo_xv.c
|
@@ -23,10 +23,15 @@
|
#include <stdint.h>
|
#include <stdbool.h>
|
#include <errno.h>
|
+#include <unistd.h>
|
+#include <sys/socket.h>
|
+#include <sys/un.h>
|
#include <X11/Xlib.h>
|
#include <X11/Xutil.h>
|
|
#include <libavutil/common.h>
|
+#include <libavutil/hwcontext.h>
|
+#include <libavutil/hwcontext_drm.h>
|
|
#include "config.h"
|
|
@@ -62,6 +67,18 @@
|
|
#define MAX_BUFFERS 10
|
|
+#define XV_DMA_CLIENT_PROP "XV_DMA_CLIENT_ID"
|
+#define XV_DMA_VER_STRIDE_PROP "XV_DMA_VER_STRIDE"
|
+#define XV_DMA_HOR_STRIDE_PROP "XV_DMA_HOR_STRIDE"
|
+#define XV_DMA_CLIENT_PATH "/tmp/.xv_dma_client"
|
+
|
+struct dma_desc {
|
+ int hor_stride;
|
+ int ver_stride;
|
+ int dma_fd;
|
+ int valid;
|
+};
|
+
|
struct xvctx {
|
struct xv_ck_info_s {
|
int method; // CK_METHOD_* constants
|
@@ -79,6 +96,8 @@ struct xvctx {
|
int current_ip_buf;
|
int num_buffers;
|
XvImage *xvimage[MAX_BUFFERS];
|
+ struct dma_desc dma_descs[MAX_BUFFERS];
|
+ int dma_client_id;
|
struct mp_image *original_image;
|
uint32_t image_width;
|
uint32_t image_height;
|
@@ -111,6 +130,7 @@ static const struct fmt_entry fmt_table[] = {
|
{IMGFMT_420P, MP_FOURCC_I420},
|
{IMGFMT_UYVY, MP_FOURCC_UYVY},
|
{IMGFMT_NV12, MP_FOURCC_NV12},
|
+ {IMGFMT_DRMPRIME, MP_FOURCC_NV12},
|
{0}
|
};
|
|
@@ -177,6 +197,144 @@ static int xv_find_atom(struct vo *vo, uint32_t xv_port, const char *name,
|
return atom;
|
}
|
|
+static int xv_check_dma_client(struct vo *vo)
|
+{
|
+ struct xvctx *ctx = vo->priv;
|
+ Atom atom;
|
+ int xv_value = 0;
|
+
|
+ if (!ctx->dma_client_id)
|
+ return -1;
|
+
|
+ atom = XInternAtom(vo->x11->display, XV_DMA_CLIENT_PROP, True);
|
+ if (atom != None)
|
+ XvGetPortAttribute(vo->x11->display, ctx->xv_port, atom, &xv_value);
|
+
|
+ if (xv_value)
|
+ return 0;
|
+
|
+ ctx->dma_client_id = 0;
|
+ return -1;
|
+}
|
+
|
+static void xv_flush_dma_client(struct vo *vo)
|
+{
|
+ struct xvctx *ctx = vo->priv;
|
+ Atom atom;
|
+
|
+ if (!ctx->dma_client_id)
|
+ return;
|
+
|
+ atom = XInternAtom(vo->x11->display, XV_DMA_CLIENT_PROP, True);
|
+ if (atom != None) {
|
+ XvSetPortAttribute(vo->x11->display, ctx->xv_port,
|
+ atom, ctx->dma_client_id);
|
+ XvGetPortAttribute(vo->x11->display, ctx->xv_port, atom,
|
+ &ctx->dma_client_id);
|
+ }
|
+}
|
+
|
+static void xv_disable_dma_client(struct vo *vo)
|
+{
|
+ struct xvctx *ctx = vo->priv;
|
+ Atom atom;
|
+
|
+ if (!ctx->dma_client_id)
|
+ return;
|
+
|
+ atom = XInternAtom(vo->x11->display, XV_DMA_CLIENT_PROP, True);
|
+ if (atom != None)
|
+ XvSetPortAttribute(vo->x11->display, ctx->xv_port, atom, 0);
|
+
|
+ ctx->dma_client_id = 0;
|
+}
|
+
|
+static void xv_send_dma_params(struct vo *vo, int hor_stride, int ver_stride)
|
+{
|
+ struct xvctx *ctx = vo->priv;
|
+ Atom atom;
|
+
|
+ if (!ctx->dma_client_id)
|
+ return;
|
+
|
+ atom = XInternAtom(vo->x11->display, XV_DMA_HOR_STRIDE_PROP, True);
|
+ if (atom == None)
|
+ goto failed;
|
+
|
+ XvSetPortAttribute(vo->x11->display, ctx->xv_port, atom, hor_stride);
|
+
|
+ atom = XInternAtom(vo->x11->display, XV_DMA_VER_STRIDE_PROP, True);
|
+ if (atom == None)
|
+ goto failed;
|
+
|
+ XvSetPortAttribute(vo->x11->display, ctx->xv_port, atom, ver_stride);
|
+
|
+ return;
|
+
|
+failed:
|
+ xv_disable_dma_client(vo);
|
+ ctx->dma_client_id = 0;
|
+}
|
+
|
+static void xv_send_dma_fd(struct vo *vo, int dma_fd)
|
+{
|
+ struct xvctx *ctx = vo->priv;
|
+ struct sockaddr_un addr;
|
+ struct iovec iov;
|
+ struct msghdr msg;
|
+ struct cmsghdr *header;
|
+ char buf[CMSG_SPACE(sizeof(int))];
|
+ int socket_fd;
|
+
|
+ if (!ctx->dma_client_id)
|
+ return;
|
+
|
+ xv_flush_dma_client(vo);
|
+
|
+ socket_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
|
+ if (socket_fd < 0)
|
+ goto failed;
|
+
|
+ addr.sun_family = AF_LOCAL;
|
+ snprintf(addr.sun_path, sizeof (addr.sun_path),
|
+ XV_DMA_CLIENT_PATH ".%d", ctx->dma_client_id);
|
+ addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
|
+
|
+ if (connect(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
+ goto failed;
|
+
|
+ iov.iov_base = buf;
|
+ iov.iov_len = 1;
|
+
|
+ msg.msg_iov = &iov;
|
+ msg.msg_iovlen = 1;
|
+ msg.msg_control = buf;
|
+ msg.msg_controllen = sizeof(buf);
|
+ msg.msg_name = NULL;
|
+ msg.msg_namelen = 0;
|
+
|
+ header = CMSG_FIRSTHDR(&msg);
|
+ header->cmsg_level = SOL_SOCKET;
|
+ header->cmsg_type = SCM_RIGHTS;
|
+
|
+ header->cmsg_len = CMSG_LEN(sizeof(int));
|
+ *((int *)CMSG_DATA(header)) = dma_fd;
|
+ sendmsg(socket_fd, &msg, 0);
|
+
|
+ /* Send am empty msg at the end */
|
+ header->cmsg_len = CMSG_LEN(0);
|
+ sendmsg(socket_fd, &msg, 0);
|
+
|
+ close(socket_fd);
|
+ return;
|
+
|
+failed:
|
+ xv_disable_dma_client(vo);
|
+
|
+ if (socket_fd >= 0)
|
+ close(socket_fd);
|
+}
|
+
|
static int xv_set_eq(struct vo *vo, uint32_t xv_port, const char *name,
|
int value)
|
{
|
@@ -508,8 +666,10 @@ static int reconfig(struct vo *vo, struct mp_image_params *params)
|
MP_VERBOSE(vo, "using Xvideo port %d for hw scaling\n", ctx->xv_port);
|
|
// In case config has been called before
|
- for (i = 0; i < ctx->num_buffers; i++)
|
+ for (i = 0; i < ctx->num_buffers; i++) {
|
deallocate_xvimage(vo, i);
|
+ ctx->dma_descs[i].valid = 0;
|
+ }
|
|
ctx->num_buffers = ctx->cfg_buffers;
|
|
@@ -683,6 +843,14 @@ static void wait_for_completion(struct vo *vo, int max_outstanding)
|
static void flip_page(struct vo *vo)
|
{
|
struct xvctx *ctx = vo->priv;
|
+ struct dma_desc *dma_desc = &ctx->dma_descs[ctx->current_buf];
|
+
|
+ if (dma_desc->valid) {
|
+ xv_send_dma_fd(vo, dma_desc->dma_fd);
|
+ xv_send_dma_params(vo, dma_desc->hor_stride, dma_desc->ver_stride);
|
+ dma_desc->valid = 0;
|
+ }
|
+
|
put_xvimage(vo, ctx->xvimage[ctx->current_buf]);
|
|
/* remember the currently visible buffer */
|
@@ -701,6 +869,26 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
|
|
struct mp_image xv_buffer = get_xv_buffer(vo, ctx->current_buf);
|
if (mpi) {
|
+ if (mpi->hwctx && !xv_check_dma_client(vo)) {
|
+ AVHWFramesContext *fctx = (void *)mpi->hwctx->data;
|
+ if (fctx->format == AV_PIX_FMT_DRM_PRIME &&
|
+ fctx->sw_format == AV_PIX_FMT_NV12) {
|
+ AVDRMFrameDescriptor *desc =
|
+ (AVDRMFrameDescriptor *)mpi->planes[0];
|
+ AVDRMLayerDescriptor *layer = &desc->layers[0];
|
+ struct dma_desc *dma_desc = &ctx->dma_descs[ctx->current_buf];
|
+
|
+ dma_desc->hor_stride = layer->planes[0].pitch;
|
+ dma_desc->ver_stride =
|
+ layer->planes[1].offset / dma_desc->hor_stride;
|
+ dma_desc->dma_fd = desc->objects[0].fd;
|
+ dma_desc->valid = 1;
|
+
|
+ // TODO: Draw osd on mmapped hw frame
|
+ goto out;
|
+ }
|
+ }
|
+
|
mp_image_copy(&xv_buffer, mpi);
|
} else {
|
mp_image_clear(&xv_buffer, 0, 0, xv_buffer.w, xv_buffer.h);
|
@@ -709,6 +897,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
|
struct mp_osd_res res = osd_res_from_image_params(vo->params);
|
osd_draw_on_image(vo->osd, res, mpi ? mpi->pts : 0, 0, &xv_buffer);
|
|
+out:
|
if (mpi != ctx->original_image) {
|
talloc_free(ctx->original_image);
|
ctx->original_image = mpi;
|
@@ -847,6 +1036,9 @@ static int preinit(struct vo *vo)
|
ctx->fo = XvListImageFormats(x11->display, ctx->xv_port,
|
(int *) &ctx->formats);
|
|
+ ctx->dma_client_id = getpid();
|
+ xv_flush_dma_client(vo);
|
+
|
MP_WARN(vo, "Warning: this legacy VO has bad quality and performance, "
|
"and will in particular result in blurry OSD and subtitles. "
|
"You should fix your graphics drivers, or not force the xv VO.\n");
|
--
|
2.17.1
|