linuxOS_AP06/debian/packages-patches/mpv/0.29.1/0002-HACK-vo_xv-Support-dma-buffer-rendering.patch
2025-06-03 12:28:32 +08:00

299 lines
8.6 KiB
Diff

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