Skip to content

Commit

Permalink
vo: hwdec: drmprime: add separate hwdecs for v4l2request
Browse files Browse the repository at this point in the history
With all the machinery in place, we can now add the v4l2request hwdecs with a
different hw device type, and a different initialisation path. This applies to
both the drmprime and drmprime_overlay hwdecs.

At the moment, the device initialisation is done in the bare minimum way, but
it can be extended to take a device path (for example) if that makes sense as
we better understand what meaningful configuration will be.

Co-authored-by: Jonas Karlman <jonas@kwiboo.se>
  • Loading branch information
philipl and Kwiboo committed Aug 19, 2024
1 parent ca9271b commit 7ceb2ae
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 45 deletions.
3 changes: 3 additions & 0 deletions video/hwdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ static const struct hwcontext_fns *const hwcontext_fns[] = {
#if HAVE_DRM
&hwcontext_fns_drmprime,
#endif
#if HAVE_V4L2REQUEST
&hwcontext_fns_v4l2request,
#endif
#if HAVE_VAAPI
&hwcontext_fns_vaapi,
#endif
Expand Down
1 change: 1 addition & 0 deletions video/hwdec.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ extern const struct hwcontext_fns hwcontext_fns_cuda;
extern const struct hwcontext_fns hwcontext_fns_d3d11;
extern const struct hwcontext_fns hwcontext_fns_drmprime;
extern const struct hwcontext_fns hwcontext_fns_dxva2;
extern const struct hwcontext_fns hwcontext_fns_v4l2request;
extern const struct hwcontext_fns hwcontext_fns_vaapi;
extern const struct hwcontext_fns hwcontext_fns_vdpau;

Expand Down
6 changes: 6 additions & 0 deletions video/out/gpu/hwdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ extern const struct ra_hwdec_driver ra_hwdec_drmprime;
extern const struct ra_hwdec_driver ra_hwdec_drmprime_overlay;
extern const struct ra_hwdec_driver ra_hwdec_aimagereader;
extern const struct ra_hwdec_driver ra_hwdec_vulkan;
extern const struct ra_hwdec_driver ra_hwdec_v4l2request;
extern const struct ra_hwdec_driver ra_hwdec_v4l2request_overlay;

const struct ra_hwdec_driver *const ra_hwdec_drivers[] = {
#if HAVE_VAAPI
Expand Down Expand Up @@ -73,6 +75,10 @@ const struct ra_hwdec_driver *const ra_hwdec_drivers[] = {
&ra_hwdec_drmprime,
&ra_hwdec_drmprime_overlay,
#endif
#if HAVE_V4L2REQUEST
&ra_hwdec_v4l2request,
&ra_hwdec_v4l2request_overlay,
#endif
#if HAVE_ANDROID_MEDIA_NDK
&ra_hwdec_aimagereader,
#endif
Expand Down
123 changes: 93 additions & 30 deletions video/out/hwdec/hwdec_drmprime.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static const char *forked_pix_fmt_names[] = {
"rpi4_10",
};

static int init(struct ra_hwdec *hw)
static int pre_init(struct ra_hwdec *hw)
{
struct priv_owner *p = hw->priv;

Expand All @@ -92,6 +92,52 @@ static int init(struct ra_hwdec *hw)
return -1;
}

return 0;
}

static int post_init(struct ra_hwdec *hw)
{
struct priv_owner *p = hw->priv;

/*
* At the moment, there is no way to discover compatible formats
* from the hwdevice_ctx, and in fact the ffmpeg hwaccels hard-code
* formats too, so we're not missing out on anything.
*/
int num_formats = 0;
MP_TARRAY_APPEND(p, p->formats, num_formats, IMGFMT_NV12);
MP_TARRAY_APPEND(p, p->formats, num_formats, IMGFMT_420P);
MP_TARRAY_APPEND(p, p->formats, num_formats, pixfmt2imgfmt(AV_PIX_FMT_NV16));
MP_TARRAY_APPEND(p, p->formats, num_formats, IMGFMT_P010);
#ifdef AV_PIX_FMT_P210
MP_TARRAY_APPEND(p, p->formats, num_formats, pixfmt2imgfmt(AV_PIX_FMT_P210));
#endif

for (int i = 0; i < MP_ARRAY_SIZE(forked_pix_fmt_names); i++) {
enum AVPixelFormat fmt = av_get_pix_fmt(forked_pix_fmt_names[i]);
if (fmt != AV_PIX_FMT_NONE) {
MP_TARRAY_APPEND(p, p->formats, num_formats, pixfmt2imgfmt(fmt));
}
}

MP_TARRAY_APPEND(p, p->formats, num_formats, 0); // terminate it

p->hwctx.hw_imgfmt = IMGFMT_DRMPRIME;
p->hwctx.supported_formats = p->formats;
p->hwctx.driver_name = hw->driver->name;
hwdec_devices_add(hw->devs, &p->hwctx);

return 0;
}

static int init_drmprime(struct ra_hwdec *hw)
{
struct priv_owner *p = hw->priv;

int ret = pre_init(hw);
if (ret != 0)
return ret;

/*
* The drm_params resource is not provided when using X11 or Wayland, but
* there are extensions that supposedly provide this information from the
Expand All @@ -114,45 +160,44 @@ static int init(struct ra_hwdec *hw)
opt_path ? opt_path : "/dev/dri/renderD128";
MP_VERBOSE(hw, "Using DRM device: %s\n", device_path);

int ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref,
AV_HWDEVICE_TYPE_DRM,
device_path, NULL, 0);
ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref,
AV_HWDEVICE_TYPE_DRM,
device_path, NULL, 0);
talloc_free(tmp);
if (ret != 0) {
MP_VERBOSE(hw, "Failed to create hwdevice_ctx: %s\n", av_err2str(ret));
return -1;
}

/*
* At the moment, there is no way to discover compatible formats
* from the hwdevice_ctx, and in fact the ffmpeg hwaccels hard-code
* formats too, so we're not missing out on anything.
*/
int num_formats = 0;
MP_TARRAY_APPEND(p, p->formats, num_formats, IMGFMT_NV12);
MP_TARRAY_APPEND(p, p->formats, num_formats, IMGFMT_420P);
MP_TARRAY_APPEND(p, p->formats, num_formats, pixfmt2imgfmt(AV_PIX_FMT_NV16));
MP_TARRAY_APPEND(p, p->formats, num_formats, IMGFMT_P010);
#ifdef AV_PIX_FMT_P210
MP_TARRAY_APPEND(p, p->formats, num_formats, pixfmt2imgfmt(AV_PIX_FMT_P210));
#endif
return post_init(hw);
}

for (int i = 0; i < MP_ARRAY_SIZE(forked_pix_fmt_names); i++) {
enum AVPixelFormat fmt = av_get_pix_fmt(forked_pix_fmt_names[i]);
if (fmt != AV_PIX_FMT_NONE) {
MP_TARRAY_APPEND(p, p->formats, num_formats, pixfmt2imgfmt(fmt));
}
}
#if HAVE_V4L2REQUEST
static int init_v4l2request(struct ra_hwdec *hw)
{
struct priv_owner *p = hw->priv;

MP_TARRAY_APPEND(p, p->formats, num_formats, 0); // terminate it
int ret = pre_init(hw);
if (ret != 0)
return ret;

p->hwctx.hw_imgfmt = IMGFMT_DRMPRIME;
p->hwctx.supported_formats = p->formats;
p->hwctx.driver_name = hw->driver->name;
hwdec_devices_add(hw->devs, &p->hwctx);
/*
* AVCodecHWConfig contains a combo of a pixel format and hwdevice type,
* correct type must be created here or hwaccel will fail.
*
* FIXME: Create hwdevice based on type in AVCodecHWConfig
*/
ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref,
AV_HWDEVICE_TYPE_V4L2REQUEST,
NULL, NULL, 0);
if (ret != 0) {
MP_VERBOSE(hw, "Failed to create hwdevice_ctx: %s\n", av_err2str(ret));
return -1;
}

return 0;
return post_init(hw);
}
#endif

static void mapper_unmap(struct ra_hwdec_mapper *mapper)
{
Expand Down Expand Up @@ -308,7 +353,24 @@ const struct ra_hwdec_driver ra_hwdec_drmprime = {
.priv_size = sizeof(struct priv_owner),
.imgfmts = {IMGFMT_DRMPRIME, 0},
.device_type = AV_HWDEVICE_TYPE_DRM,
.init = init,
.init = init_drmprime,
.uninit = uninit,
.mapper = &(const struct ra_hwdec_mapper_driver){
.priv_size = sizeof(struct dmabuf_interop_priv),
.init = mapper_init,
.uninit = mapper_uninit,
.map = mapper_map,
.unmap = mapper_unmap,
},
};

#if HAVE_V4L2REQUEST
const struct ra_hwdec_driver ra_hwdec_v4l2request = {
.name = "v4l2request",
.priv_size = sizeof(struct priv_owner),
.imgfmts = {IMGFMT_DRMPRIME, 0},
.device_type = AV_HWDEVICE_TYPE_V4L2REQUEST,
.init = init_v4l2request,
.uninit = uninit,
.mapper = &(const struct ra_hwdec_mapper_driver){
.priv_size = sizeof(struct dmabuf_interop_priv),
Expand All @@ -318,3 +380,4 @@ const struct ra_hwdec_driver ra_hwdec_drmprime = {
.unmap = mapper_unmap,
},
};
#endif
77 changes: 69 additions & 8 deletions video/out/hwdec/hwdec_drmprime_overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ static void uninit(struct ra_hwdec *hw)
}
}

static int init(struct ra_hwdec *hw)
static int pre_init(struct ra_hwdec *hw)
{
struct priv *p = hw->priv;
int draw_plane, drmprime_video_plane;
Expand All @@ -267,15 +267,15 @@ static int init(struct ra_hwdec *hw)
drm_params->connector_id, draw_plane, drmprime_video_plane);
if (!p->ctx) {
mp_err(p->log, "Failed to retrieve DRM atomic context.\n");
goto err;
return -1;
}
if (!p->ctx->drmprime_video_plane) {
mp_warn(p->log, "No drmprime video plane. You might need to specify it manually using --drm-drmprime-video-plane\n");
goto err;
return -1;
}
} else {
mp_verbose(p->log, "Failed to retrieve DRM fd from native display.\n");
goto err;
return -1;
}

drmModeCrtcPtr crtc;
Expand All @@ -289,7 +289,7 @@ static int init(struct ra_hwdec *hw)
uint64_t has_prime;
if (drmGetCap(p->ctx->fd, DRM_CAP_PRIME, &has_prime) < 0) {
MP_ERR(hw, "Card does not support prime handles.\n");
goto err;
return -1;
}

if (has_prime) {
Expand All @@ -298,14 +298,25 @@ static int init(struct ra_hwdec *hw)

disable_video_plane(hw);

return 0;
}

static int init_drmprime(struct ra_hwdec *hw)
{
struct priv *p = hw->priv;

int ret = pre_init(hw);
if (ret != 0)
goto err;

p->hwctx = (struct mp_hwdec_ctx) {
.driver_name = hw->driver->name,
.hw_imgfmt = IMGFMT_DRMPRIME,
};

char *device = drmGetDeviceNameFromFd2(p->ctx->fd);
int ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref,
AV_HWDEVICE_TYPE_DRM, device, NULL, 0);
ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref,
AV_HWDEVICE_TYPE_DRM, device, NULL, 0);

if (device)
free(device);
Expand All @@ -324,12 +335,62 @@ static int init(struct ra_hwdec *hw)
return -1;
}

#if HAVE_V4L2REQUEST
static int init_v4l2request(struct ra_hwdec *hw)
{
struct priv *p = hw->priv;

int ret = pre_init(hw);
if (ret != 0)
goto err;

p->hwctx = (struct mp_hwdec_ctx) {
.driver_name = hw->driver->name,
.hw_imgfmt = IMGFMT_DRMPRIME,
};

/*
* AVCodecHWConfig contains a combo of a pixel format and hwdevice type,
* correct type must be created here or hwaccel will fail.
*
* FIXME: Create hwdevice based on type in AVCodecHWConfig
*/
ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref,
AV_HWDEVICE_TYPE_V4L2REQUEST,
NULL, NULL, 0);
if (ret != 0) {
MP_VERBOSE(hw, "Failed to create hwdevice_ctx: %s\n", av_err2str(ret));
goto err;
}

hwdec_devices_add(hw->devs, &p->hwctx);

return 0;

err:
uninit(hw);
return -1;
}
#endif

const struct ra_hwdec_driver ra_hwdec_drmprime_overlay = {
.name = "drmprime-overlay",
.priv_size = sizeof(struct priv),
.imgfmts = {IMGFMT_DRMPRIME, 0},
.device_type = AV_HWDEVICE_TYPE_DRM,
.init = init,
.init = init_drmprime,
.overlay_frame = overlay_frame,
.uninit = uninit,
};

#if HAVE_V4L2REQUEST
const struct ra_hwdec_driver ra_hwdec_v4l2request_overlay = {
.name = "v4l2request-overlay",
.priv_size = sizeof(struct priv),
.imgfmts = {IMGFMT_DRMPRIME, 0},
.device_type = AV_HWDEVICE_TYPE_V4L2REQUEST,
.init = init_v4l2request,
.overlay_frame = overlay_frame,
.uninit = uninit,
};
#endif
13 changes: 6 additions & 7 deletions video/out/vo_dmabuf_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -820,13 +820,12 @@ static int preinit(struct vo *vo)
}
}

for (int i = 0; i < p->hwdec_ctx.num_hwdecs; i++) {
struct ra_hwdec *hw = p->hwdec_ctx.hwdecs[i];
if (ra_get_native_resource(p->ctx->ra, "VADisplay")) {
p->hwdec_type = HWDEC_VAAPI;
} else if (strcmp(hw->driver->name, "drmprime") == 0) {
p->hwdec_type = HWDEC_DRMPRIME;
}
// TODO: Handle the possibility of multiple loaded hwdecs that support
// different image formats.
if (ra_get_native_resource(p->ctx->ra, "VADisplay")) {
p->hwdec_type = HWDEC_VAAPI;
} else {
p->hwdec_type = HWDEC_DRMPRIME;
}

if (p->hwdec_type == HWDEC_NONE) {
Expand Down
34 changes: 34 additions & 0 deletions video/v4l2request.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/

#include <libavutil/hwcontext.h>

#include "hwdec.h"

static struct AVBufferRef *v4l2request_create_standalone(struct mpv_global *global,
struct mp_log *log, struct hwcontext_create_dev_params *params)
{
AVBufferRef* ref = NULL;
av_hwdevice_ctx_create(&ref, AV_HWDEVICE_TYPE_V4L2REQUEST, NULL, NULL, 0);

return ref;
}

const struct hwcontext_fns hwcontext_fns_v4l2request = {
.av_hwdevice_type = AV_HWDEVICE_TYPE_V4L2REQUEST,
.create_dev = v4l2request_create_standalone,
};

0 comments on commit 7ceb2ae

Please sign in to comment.