mirror of
https://github.com/mpv-player/mpv
synced 2024-10-22 08:51:57 +02:00
video: handle hwdec screenshots differently
Instead of converting the hw surface to an image in the VO, provide a generic way to convet hw surfaces, and use this in the screenshot code. It's all relatively straightforward, except vdpau is being terrible. It needs a huge chunk of new code, because copying back is not simple.
This commit is contained in:
parent
e9ac3fc3a1
commit
74581a6106
@ -343,6 +343,16 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode)
|
|||||||
|
|
||||||
image = args.out_image;
|
image = args.out_image;
|
||||||
if (image) {
|
if (image) {
|
||||||
|
if (mpctx->d_video && mpctx->d_video->hwdec_info) {
|
||||||
|
struct mp_hwdec_ctx *ctx = mpctx->d_video->hwdec_info->hwctx;
|
||||||
|
struct mp_image *nimage = NULL;
|
||||||
|
if (ctx && ctx->download_image)
|
||||||
|
nimage = ctx->download_image(ctx, image, NULL);
|
||||||
|
if (nimage) {
|
||||||
|
talloc_free(image);
|
||||||
|
image = nimage;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mode == MODE_SUBTITLES && !args.has_osd)
|
if (mode == MODE_SUBTITLES && !args.has_osd)
|
||||||
add_subs(mpctx, image);
|
add_subs(mpctx, image);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,15 @@ struct mp_hwdec_ctx {
|
|||||||
// API-specific, not needed by all backends.
|
// API-specific, not needed by all backends.
|
||||||
struct mp_vdpau_ctx *vdpau_ctx;
|
struct mp_vdpau_ctx *vdpau_ctx;
|
||||||
struct mp_vaapi_ctx *vaapi_ctx;
|
struct mp_vaapi_ctx *vaapi_ctx;
|
||||||
|
|
||||||
|
// Optional.
|
||||||
|
// Allocates a software image from the pool, downloads the hw image from
|
||||||
|
// mpi, and returns it.
|
||||||
|
// pool can be NULL (then just use straight allocation).
|
||||||
|
// Return NULL on error or if mpi has the wrong format.
|
||||||
|
struct mp_image *(*download_image)(struct mp_hwdec_ctx *ctx,
|
||||||
|
struct mp_image *mpi,
|
||||||
|
struct mp_image_pool *swpool);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used to communicate hardware decoder API handles from VO to video decoder.
|
// Used to communicate hardware decoder API handles from VO to video decoder.
|
||||||
|
@ -372,6 +372,7 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src)
|
|||||||
dst->params.chroma_location = src->params.chroma_location;
|
dst->params.chroma_location = src->params.chroma_location;
|
||||||
dst->params.outputlevels = src->params.outputlevels;
|
dst->params.outputlevels = src->params.outputlevels;
|
||||||
}
|
}
|
||||||
|
mp_image_params_guess_csp(&dst->params); // ensure colorspace consistency
|
||||||
if ((dst->fmt.flags & MP_IMGFLAG_PAL) && (src->fmt.flags & MP_IMGFLAG_PAL)) {
|
if ((dst->fmt.flags & MP_IMGFLAG_PAL) && (src->fmt.flags & MP_IMGFLAG_PAL)) {
|
||||||
if (dst->planes[1] && src->planes[1])
|
if (dst->planes[1] && src->planes[1])
|
||||||
memcpy(dst->planes[1], src->planes[1], MP_PALETTE_SIZE);
|
memcpy(dst->planes[1], src->planes[1], MP_PALETTE_SIZE);
|
||||||
|
@ -43,9 +43,7 @@ struct gl_hwdec_driver {
|
|||||||
// Undo map_image(). The user of map_image() calls this when the textures
|
// Undo map_image(). The user of map_image() calls this when the textures
|
||||||
// are not needed anymore.
|
// are not needed anymore.
|
||||||
void (*unmap_image)(struct gl_hwdec *hw);
|
void (*unmap_image)(struct gl_hwdec *hw);
|
||||||
// Return a mp_image downloaded from the GPU (optional)
|
|
||||||
struct mp_image *(*download_image)(struct gl_hwdec *hw,
|
|
||||||
struct mp_image *hw_image);
|
|
||||||
void (*destroy)(struct gl_hwdec *hw);
|
void (*destroy)(struct gl_hwdec *hw);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,14 +22,42 @@
|
|||||||
#include <OpenGL/OpenGL.h>
|
#include <OpenGL/OpenGL.h>
|
||||||
#include <OpenGL/CGLIOSurface.h>
|
#include <OpenGL/CGLIOSurface.h>
|
||||||
|
|
||||||
#include "video/decode/dec_video.h"
|
#include "video/mp_image_pool.h"
|
||||||
#include "gl_hwdec.h"
|
#include "gl_hwdec.h"
|
||||||
|
|
||||||
struct priv {
|
struct priv {
|
||||||
CVPixelBufferRef pbuf;
|
CVPixelBufferRef pbuf;
|
||||||
GLuint gl_texture;
|
GLuint gl_texture;
|
||||||
|
struct mp_hwdec_ctx hwctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mp_image *download_image(struct mp_hwdec_ctx *ctx,
|
||||||
|
struct mp_image *hw_image,
|
||||||
|
struct mp_image_pool *swpool)
|
||||||
|
{
|
||||||
|
if (hw_image->imgfmt != IMGFMT_VDA)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
CVPixelBufferRef pbuf = (CVPixelBufferRef)hw_image->planes[3];
|
||||||
|
CVPixelBufferLockBaseAddress(pbuf, 0);
|
||||||
|
void *base = CVPixelBufferGetBaseAddress(pbuf);
|
||||||
|
size_t width = CVPixelBufferGetWidth(pbuf);
|
||||||
|
size_t height = CVPixelBufferGetHeight(pbuf);
|
||||||
|
size_t stride = CVPixelBufferGetBytesPerRow(pbuf);
|
||||||
|
|
||||||
|
struct mp_image img = {0};
|
||||||
|
mp_image_setfmt(&img, IMGFMT_UYVY);
|
||||||
|
mp_image_set_size(&img, width, height);
|
||||||
|
img.planes[0] = base;
|
||||||
|
img.stride[0] = stride;
|
||||||
|
mp_image_copy_attributes(&img, hw_image);
|
||||||
|
|
||||||
|
struct mp_image *image = mp_image_pool_new_copy(swpool, &img);
|
||||||
|
CVPixelBufferUnlockBaseAddress(pbuf, 0);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
static bool check_hwdec(struct gl_hwdec *hw)
|
static bool check_hwdec(struct gl_hwdec *hw)
|
||||||
{
|
{
|
||||||
if (hw->gl_texture_target != GL_TEXTURE_RECTANGLE) {
|
if (hw->gl_texture_target != GL_TEXTURE_RECTANGLE) {
|
||||||
@ -60,6 +88,9 @@ static int create(struct gl_hwdec *hw)
|
|||||||
if (!check_hwdec(hw))
|
if (!check_hwdec(hw))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
hw->hwctx = &p->hwctx;
|
||||||
|
hw->hwctx->download_image = download_image;
|
||||||
|
|
||||||
GL *gl = hw->gl;
|
GL *gl = hw->gl;
|
||||||
gl->GenTextures(1, &p->gl_texture);
|
gl->GenTextures(1, &p->gl_texture);
|
||||||
|
|
||||||
@ -104,28 +135,6 @@ static int map_image(struct gl_hwdec *hw, struct mp_image *hw_image,
|
|||||||
|
|
||||||
static void unmap_image(struct gl_hwdec *hw) { }
|
static void unmap_image(struct gl_hwdec *hw) { }
|
||||||
|
|
||||||
static struct mp_image *download_image(struct gl_hwdec *hw,
|
|
||||||
struct mp_image *hw_image)
|
|
||||||
{
|
|
||||||
CVPixelBufferRef pbuf = (CVPixelBufferRef)hw_image->planes[3];
|
|
||||||
CVPixelBufferLockBaseAddress(pbuf, 0);
|
|
||||||
void *base = CVPixelBufferGetBaseAddress(pbuf);
|
|
||||||
size_t width = CVPixelBufferGetWidth(pbuf);
|
|
||||||
size_t height = CVPixelBufferGetHeight(pbuf);
|
|
||||||
size_t stride = CVPixelBufferGetBytesPerRow(pbuf);
|
|
||||||
|
|
||||||
struct mp_image img = {0};
|
|
||||||
mp_image_setfmt(&img, IMGFMT_UYVY);
|
|
||||||
mp_image_set_size(&img, width, height);
|
|
||||||
img.planes[0] = base;
|
|
||||||
img.stride[0] = stride;
|
|
||||||
|
|
||||||
struct mp_image *image = mp_image_new_copy(&img);
|
|
||||||
CVPixelBufferUnlockBaseAddress(pbuf, 0);
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroy(struct gl_hwdec *hw)
|
static void destroy(struct gl_hwdec *hw)
|
||||||
{
|
{
|
||||||
struct priv *p = hw->priv;
|
struct priv *p = hw->priv;
|
||||||
@ -136,7 +145,6 @@ static void destroy(struct gl_hwdec *hw)
|
|||||||
p->gl_texture = 0;
|
p->gl_texture = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const struct gl_hwdec_driver gl_hwdec_vda = {
|
const struct gl_hwdec_driver gl_hwdec_vda = {
|
||||||
.api_name = "vda",
|
.api_name = "vda",
|
||||||
.imgfmt = IMGFMT_VDA,
|
.imgfmt = IMGFMT_VDA,
|
||||||
@ -144,6 +152,5 @@ const struct gl_hwdec_driver gl_hwdec_vda = {
|
|||||||
.reinit = reinit,
|
.reinit = reinit,
|
||||||
.map_image = map_image,
|
.map_image = map_image,
|
||||||
.unmap_image = unmap_image,
|
.unmap_image = unmap_image,
|
||||||
.download_image = download_image,
|
|
||||||
.destroy = destroy,
|
.destroy = destroy,
|
||||||
};
|
};
|
||||||
|
@ -2017,16 +2017,14 @@ struct mp_image *gl_video_download_image(struct gl_video *p)
|
|||||||
|
|
||||||
struct video_image *vimg = &p->image;
|
struct video_image *vimg = &p->image;
|
||||||
|
|
||||||
if (!p->have_image || !gl->GetTexImage)
|
if (!p->have_image)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (p->hwdec_active && p->hwdec->driver->download_image) {
|
if (p->hwdec_active)
|
||||||
struct mp_image *dlimage =
|
return mp_image_new_ref(vimg->hwimage);
|
||||||
p->hwdec->driver->download_image(p->hwdec, vimg->hwimage);
|
|
||||||
if (dlimage)
|
if (!gl->GetTexImage)
|
||||||
mp_image_set_attributes(dlimage, &p->image_params);
|
return NULL;
|
||||||
return dlimage;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_image_textures(p, vimg, NULL);
|
set_image_textures(p, vimg, NULL);
|
||||||
|
|
||||||
|
@ -303,14 +303,7 @@ static struct mp_image *get_screenshot(struct priv *p)
|
|||||||
struct mp_image *hwimg = p->output_surfaces[p->visible_surface];
|
struct mp_image *hwimg = p->output_surfaces[p->visible_surface];
|
||||||
if (!hwimg)
|
if (!hwimg)
|
||||||
return NULL;
|
return NULL;
|
||||||
struct mp_image *img = va_surface_download(hwimg, NULL);
|
return mp_image_new_ref(hwimg);
|
||||||
if (!img)
|
|
||||||
return NULL;
|
|
||||||
struct mp_image_params params = p->image_params;
|
|
||||||
params.imgfmt = img->imgfmt;
|
|
||||||
mp_image_params_guess_csp(¶ms); // ensure colorspace consistency
|
|
||||||
mp_image_set_params(img, ¶ms);
|
|
||||||
return img;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_subpicture(struct priv *p, struct vaapi_osd_image *img)
|
static void free_subpicture(struct priv *p, struct vaapi_osd_image *img)
|
||||||
|
@ -80,7 +80,6 @@ struct vdpctx {
|
|||||||
VdpPresentationQueue flip_queue;
|
VdpPresentationQueue flip_queue;
|
||||||
|
|
||||||
VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES];
|
VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES];
|
||||||
VdpOutputSurface screenshot_surface;
|
|
||||||
int num_output_surfaces;
|
int num_output_surfaces;
|
||||||
VdpOutputSurface black_pixel;
|
VdpOutputSurface black_pixel;
|
||||||
|
|
||||||
@ -176,24 +175,16 @@ static int render_video_to_output_surface(struct vo *vo,
|
|||||||
"vdp_presentation_queue_block_until_surface_idle");
|
"vdp_presentation_queue_block_until_surface_idle");
|
||||||
|
|
||||||
if (vc->rgb_mode) {
|
if (vc->rgb_mode) {
|
||||||
VdpOutputSurface surface = (uintptr_t)mpi->planes[3];
|
// Clear the borders between video and window (if there are any).
|
||||||
|
// For some reason, video_mixer_render doesn't need it for YUV.
|
||||||
int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0;
|
int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0;
|
||||||
vdp_st = vdp->output_surface_render_output_surface(output_surface,
|
vdp_st = vdp->output_surface_render_output_surface(output_surface,
|
||||||
NULL, vc->black_pixel,
|
NULL, vc->black_pixel,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
flags);
|
flags);
|
||||||
CHECK_VDP_WARNING(vo, "Error clearing screen");
|
CHECK_VDP_WARNING(vo, "Error clearing screen");
|
||||||
vdp_st = vdp->output_surface_render_output_surface(output_surface,
|
|
||||||
output_rect,
|
|
||||||
surface,
|
|
||||||
video_rect,
|
|
||||||
NULL, NULL, flags);
|
|
||||||
CHECK_VDP_WARNING(vo, "Error when calling "
|
|
||||||
"vdp_output_surface_render_output_surface");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct mp_vdpau_mixer_frame *frame = mp_vdpau_mixed_frame_get(mpi);
|
struct mp_vdpau_mixer_frame *frame = mp_vdpau_mixed_frame_get(mpi);
|
||||||
struct mp_vdpau_mixer_opts opts = {0};
|
struct mp_vdpau_mixer_opts opts = {0};
|
||||||
if (frame)
|
if (frame)
|
||||||
@ -344,12 +335,6 @@ static void free_video_specific(struct vo *vo)
|
|||||||
|
|
||||||
forget_frames(vo, false);
|
forget_frames(vo, false);
|
||||||
|
|
||||||
if (vc->screenshot_surface != VDP_INVALID_HANDLE) {
|
|
||||||
vdp_st = vdp->output_surface_destroy(vc->screenshot_surface);
|
|
||||||
CHECK_VDP_WARNING(vo, "Error when calling vdp_output_surface_destroy");
|
|
||||||
}
|
|
||||||
vc->screenshot_surface = VDP_INVALID_HANDLE;
|
|
||||||
|
|
||||||
if (vc->black_pixel != VDP_INVALID_HANDLE) {
|
if (vc->black_pixel != VDP_INVALID_HANDLE) {
|
||||||
vdp_st = vdp->output_surface_destroy(vc->black_pixel);
|
vdp_st = vdp->output_surface_destroy(vc->black_pixel);
|
||||||
CHECK_VDP_WARNING(vo, "Error when calling vdp_output_surface_destroy");
|
CHECK_VDP_WARNING(vo, "Error when calling vdp_output_surface_destroy");
|
||||||
@ -399,7 +384,6 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
|
|||||||
vc->flip_target = VDP_INVALID_HANDLE;
|
vc->flip_target = VDP_INVALID_HANDLE;
|
||||||
for (int i = 0; i < MAX_OUTPUT_SURFACES; i++)
|
for (int i = 0; i < MAX_OUTPUT_SURFACES; i++)
|
||||||
vc->output_surfaces[i] = VDP_INVALID_HANDLE;
|
vc->output_surfaces[i] = VDP_INVALID_HANDLE;
|
||||||
vc->screenshot_surface = VDP_INVALID_HANDLE;
|
|
||||||
vc->vdp_device = VDP_INVALID_HANDLE;
|
vc->vdp_device = VDP_INVALID_HANDLE;
|
||||||
for (int i = 0; i < MAX_OSD_PARTS; i++) {
|
for (int i = 0; i < MAX_OSD_PARTS; i++) {
|
||||||
struct osd_bitmap_surface *sfc = &vc->osd_surfaces[i];
|
struct osd_bitmap_surface *sfc = &vc->osd_surfaces[i];
|
||||||
@ -878,30 +862,6 @@ static struct mp_image *read_output_surface(struct vo *vo,
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mp_image *get_screenshot(struct vo *vo)
|
|
||||||
{
|
|
||||||
struct vdpctx *vc = vo->priv;
|
|
||||||
VdpStatus vdp_st;
|
|
||||||
struct vdp_functions *vdp = vc->vdp;
|
|
||||||
|
|
||||||
if (!vo->params)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (vc->screenshot_surface == VDP_INVALID_HANDLE) {
|
|
||||||
vdp_st = vdp->output_surface_create(vc->vdp_device,
|
|
||||||
OUTPUT_RGBA_FORMAT,
|
|
||||||
vo->params->d_w, vo->params->d_h,
|
|
||||||
&vc->screenshot_surface);
|
|
||||||
CHECK_VDP_WARNING(vo, "Error when calling vdp_output_surface_create");
|
|
||||||
}
|
|
||||||
|
|
||||||
VdpRect in = { .x1 = vo->params->w, .y1 = vo->params->h };
|
|
||||||
VdpRect out = { .x1 = vo->params->d_w, .y1 = vo->params->d_h };
|
|
||||||
render_video_to_output_surface(vo, vc->screenshot_surface, &out, &in);
|
|
||||||
|
|
||||||
return read_output_surface(vo, vc->screenshot_surface, out.x1, out.y1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mp_image *get_window_screenshot(struct vo *vo)
|
static struct mp_image *get_window_screenshot(struct vo *vo)
|
||||||
{
|
{
|
||||||
struct vdpctx *vc = vo->priv;
|
struct vdpctx *vc = vo->priv;
|
||||||
@ -1092,10 +1052,12 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
|||||||
if (!status_ok(vo))
|
if (!status_ok(vo))
|
||||||
return false;
|
return false;
|
||||||
struct voctrl_screenshot_args *args = data;
|
struct voctrl_screenshot_args *args = data;
|
||||||
if (args->full_window)
|
if (args->full_window) {
|
||||||
args->out_image = get_window_screenshot(vo);
|
args->out_image = get_window_screenshot(vo);
|
||||||
else
|
} else {
|
||||||
args->out_image = get_screenshot(vo);
|
args->out_image =
|
||||||
|
vc->current_image ? mp_image_new_ref(vc->current_image) : NULL;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case VOCTRL_GET_PREF_DEINT:
|
case VOCTRL_GET_PREF_DEINT:
|
||||||
|
@ -84,6 +84,13 @@ uint32_t va_fourcc_from_imgfmt(int imgfmt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct mp_image *ctx_download_image(struct mp_hwdec_ctx *ctx,
|
||||||
|
struct mp_image *mpi,
|
||||||
|
struct mp_image_pool *swpool)
|
||||||
|
{
|
||||||
|
return va_surface_download(mpi, swpool);
|
||||||
|
}
|
||||||
|
|
||||||
struct va_image_formats {
|
struct va_image_formats {
|
||||||
VAImageFormat *entries;
|
VAImageFormat *entries;
|
||||||
int num;
|
int num;
|
||||||
@ -125,6 +132,7 @@ struct mp_vaapi_ctx *va_initialize(VADisplay *display, struct mp_log *plog)
|
|||||||
.hwctx = {
|
.hwctx = {
|
||||||
.priv = res,
|
.priv = res,
|
||||||
.vaapi_ctx = res,
|
.vaapi_ctx = res,
|
||||||
|
.download_image = ctx_download_image,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
mpthread_mutex_init_recursive(&res->lock);
|
mpthread_mutex_init_recursive(&res->lock);
|
||||||
@ -405,12 +413,12 @@ static struct mp_image *try_download(struct mp_image *src,
|
|||||||
struct mp_image *dst = NULL;
|
struct mp_image *dst = NULL;
|
||||||
struct mp_image tmp;
|
struct mp_image tmp;
|
||||||
if (va_image_map(p->ctx, image, &tmp)) {
|
if (va_image_map(p->ctx, image, &tmp)) {
|
||||||
dst = pool ? mp_image_pool_get(pool, tmp.imgfmt, tmp.w, tmp.h)
|
dst = mp_image_pool_get(pool, tmp.imgfmt, tmp.w, tmp.h);
|
||||||
: mp_image_alloc(tmp.imgfmt, tmp.w, tmp.h);
|
|
||||||
if (dst)
|
if (dst)
|
||||||
mp_image_copy(dst, &tmp);
|
mp_image_copy(dst, &tmp);
|
||||||
va_image_unmap(p->ctx, image);
|
va_image_unmap(p->ctx, image);
|
||||||
}
|
}
|
||||||
|
mp_image_copy_attributes(dst, src);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,76 @@
|
|||||||
#include "osdep/timer.h"
|
#include "osdep/timer.h"
|
||||||
|
|
||||||
#include "video/out/x11_common.h"
|
#include "video/out/x11_common.h"
|
||||||
#include "video/img_format.h"
|
#include "img_format.h"
|
||||||
#include "video/mp_image.h"
|
#include "mp_image.h"
|
||||||
|
#include "mp_image_pool.h"
|
||||||
|
#include "vdpau_mixer.h"
|
||||||
|
|
||||||
|
static struct mp_image *download_image(struct mp_hwdec_ctx *hwctx,
|
||||||
|
struct mp_image *mpi,
|
||||||
|
struct mp_image_pool *swpool)
|
||||||
|
{
|
||||||
|
struct mp_vdpau_ctx *ctx = hwctx->vdpau_ctx;
|
||||||
|
struct vdp_functions *vdp = &ctx->vdp;
|
||||||
|
VdpStatus vdp_st;
|
||||||
|
|
||||||
|
struct mp_image *res = NULL;
|
||||||
|
int w = mpi->params.d_w;
|
||||||
|
int h = mpi->params.d_h;
|
||||||
|
|
||||||
|
// Abuse this lock for our own purposes. It could use its own lock instead.
|
||||||
|
pthread_mutex_lock(&ctx->pool_lock);
|
||||||
|
|
||||||
|
if (ctx->getimg_surface == VDP_INVALID_HANDLE ||
|
||||||
|
ctx->getimg_w < w || ctx->getimg_h < h)
|
||||||
|
{
|
||||||
|
if (ctx->getimg_surface != VDP_INVALID_HANDLE) {
|
||||||
|
vdp_st = vdp->output_surface_destroy(ctx->getimg_surface);
|
||||||
|
CHECK_VDP_WARNING(ctx, "Error when calling vdp_output_surface_destroy");
|
||||||
|
}
|
||||||
|
ctx->getimg_surface = VDP_INVALID_HANDLE;
|
||||||
|
vdp_st = vdp->output_surface_create(ctx->vdp_device,
|
||||||
|
VDP_RGBA_FORMAT_B8G8R8A8, w, h,
|
||||||
|
&ctx->getimg_surface);
|
||||||
|
CHECK_VDP_WARNING(ctx, "Error when calling vdp_output_surface_create");
|
||||||
|
if (vdp_st != VDP_STATUS_OK)
|
||||||
|
goto error;
|
||||||
|
ctx->getimg_w = w;
|
||||||
|
ctx->getimg_h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->getimg_mixer)
|
||||||
|
ctx->getimg_mixer = mp_vdpau_mixer_create(ctx, ctx->log);
|
||||||
|
|
||||||
|
VdpRect in = { .x1 = mpi->w, .y1 = mpi->h };
|
||||||
|
VdpRect out = { .x1 = w, .y1 = h };
|
||||||
|
if (mp_vdpau_mixer_render(ctx->getimg_mixer, NULL, ctx->getimg_surface, &out,
|
||||||
|
mpi, &in) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
res = mp_image_pool_get(swpool, IMGFMT_BGR32, ctx->getimg_w, ctx->getimg_h);
|
||||||
|
if (!res)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
void *dst_planes[] = { res->planes[0] };
|
||||||
|
uint32_t dst_pitches[] = { res->stride[0] };
|
||||||
|
vdp_st = vdp->output_surface_get_bits_native(ctx->getimg_surface, NULL,
|
||||||
|
dst_planes, dst_pitches);
|
||||||
|
CHECK_VDP_WARNING(ctx, "Error when calling vdp_output_surface_get_bits_native");
|
||||||
|
if (vdp_st != VDP_STATUS_OK)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
mp_image_set_size(res, w, h);
|
||||||
|
mp_image_copy_attributes(res, mpi);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&ctx->pool_lock);
|
||||||
|
return res;
|
||||||
|
error:
|
||||||
|
talloc_free(res);
|
||||||
|
MP_WARN(ctx, "Error copying image from GPU.\n");
|
||||||
|
pthread_mutex_unlock(&ctx->pool_lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void mark_vdpau_objects_uninitialized(struct mp_vdpau_ctx *ctx)
|
static void mark_vdpau_objects_uninitialized(struct mp_vdpau_ctx *ctx)
|
||||||
{
|
{
|
||||||
@ -305,7 +373,9 @@ struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11
|
|||||||
.hwctx = {
|
.hwctx = {
|
||||||
.priv = ctx,
|
.priv = ctx,
|
||||||
.vdpau_ctx = ctx,
|
.vdpau_ctx = ctx,
|
||||||
|
.download_image = download_image,
|
||||||
},
|
},
|
||||||
|
.getimg_surface = VDP_INVALID_HANDLE,
|
||||||
};
|
};
|
||||||
mpthread_mutex_init_recursive(&ctx->preempt_lock);
|
mpthread_mutex_init_recursive(&ctx->preempt_lock);
|
||||||
pthread_mutex_init(&ctx->pool_lock, NULL);
|
pthread_mutex_init(&ctx->pool_lock, NULL);
|
||||||
@ -337,6 +407,13 @@ void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->getimg_mixer)
|
||||||
|
mp_vdpau_mixer_destroy(ctx->getimg_mixer);
|
||||||
|
if (ctx->getimg_surface != VDP_INVALID_HANDLE) {
|
||||||
|
vdp_st = vdp->output_surface_destroy(ctx->getimg_surface);
|
||||||
|
CHECK_VDP_WARNING(ctx, "Error when calling vdp_output_surface_destroy");
|
||||||
|
}
|
||||||
|
|
||||||
if (vdp->device_destroy && ctx->vdp_device != VDP_INVALID_HANDLE) {
|
if (vdp->device_destroy && ctx->vdp_device != VDP_INVALID_HANDLE) {
|
||||||
vdp_st = vdp->device_destroy(ctx->vdp_device);
|
vdp_st = vdp->device_destroy(ctx->vdp_device);
|
||||||
CHECK_VDP_WARNING(ctx, "Error when calling vdp_device_destroy");
|
CHECK_VDP_WARNING(ctx, "Error when calling vdp_device_destroy");
|
||||||
|
@ -12,14 +12,17 @@
|
|||||||
#include "common/msg.h"
|
#include "common/msg.h"
|
||||||
#include "hwdec.h"
|
#include "hwdec.h"
|
||||||
|
|
||||||
#define CHECK_VDP_ERROR(ctx, message) \
|
#define CHECK_VDP_ERROR_ST(ctx, message, statement) \
|
||||||
do { \
|
do { \
|
||||||
if (vdp_st != VDP_STATUS_OK) { \
|
if (vdp_st != VDP_STATUS_OK) { \
|
||||||
MP_ERR(ctx, "%s: %s\n", message, vdp->get_error_string(vdp_st)); \
|
MP_ERR(ctx, "%s: %s\n", message, vdp->get_error_string(vdp_st)); \
|
||||||
return -1; \
|
statement \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define CHECK_VDP_ERROR(ctx, message) \
|
||||||
|
CHECK_VDP_ERROR_ST(ctx, message, return -1;)
|
||||||
|
|
||||||
#define CHECK_VDP_WARNING(ctx, message) \
|
#define CHECK_VDP_WARNING(ctx, message) \
|
||||||
do { \
|
do { \
|
||||||
if (vdp_st != VDP_STATUS_OK) \
|
if (vdp_st != VDP_STATUS_OK) \
|
||||||
@ -71,6 +74,9 @@ struct mp_vdpau_ctx {
|
|||||||
bool in_use;
|
bool in_use;
|
||||||
int64_t age;
|
int64_t age;
|
||||||
} video_surfaces[MAX_VIDEO_SURFACES];
|
} video_surfaces[MAX_VIDEO_SURFACES];
|
||||||
|
struct mp_vdpau_mixer *getimg_mixer;
|
||||||
|
VdpOutputSurface getimg_surface;
|
||||||
|
int getimg_w, getimg_h;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11);
|
struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11);
|
||||||
|
@ -43,3 +43,5 @@ VDP_FUNCTION(VdpVideoMixerSetFeatureEnables, VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE
|
|||||||
VDP_FUNCTION(VdpVideoSurfaceCreate, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, video_surface_create)
|
VDP_FUNCTION(VdpVideoSurfaceCreate, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, video_surface_create)
|
||||||
VDP_FUNCTION(VdpVideoSurfaceDestroy, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, video_surface_destroy)
|
VDP_FUNCTION(VdpVideoSurfaceDestroy, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, video_surface_destroy)
|
||||||
VDP_FUNCTION(VdpVideoSurfacePutBitsYCbCr, VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR, video_surface_put_bits_y_cb_cr)
|
VDP_FUNCTION(VdpVideoSurfacePutBitsYCbCr, VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR, video_surface_put_bits_y_cb_cr)
|
||||||
|
VDP_FUNCTION(VdpVideoSurfaceGetBitsYCbCr, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, video_surface_get_bits_y_cb_cr)
|
||||||
|
VDP_FUNCTION(VdpVideoSurfaceGetParameters, VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, video_surface_get_parameters)
|
||||||
|
@ -221,7 +221,21 @@ int mp_vdpau_mixer_render(struct mp_vdpau_mixer *mixer,
|
|||||||
struct vdp_functions *vdp = &mixer->ctx->vdp;
|
struct vdp_functions *vdp = &mixer->ctx->vdp;
|
||||||
VdpStatus vdp_st;
|
VdpStatus vdp_st;
|
||||||
|
|
||||||
assert(video->imgfmt == IMGFMT_VDPAU);
|
if (video->imgfmt == IMGFMT_VDPAU_OUTPUT) {
|
||||||
|
VdpOutputSurface surface = (uintptr_t)video->planes[3];
|
||||||
|
int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0;
|
||||||
|
vdp_st = vdp->output_surface_render_output_surface(output,
|
||||||
|
output_rect,
|
||||||
|
surface,
|
||||||
|
video_rect,
|
||||||
|
NULL, NULL, flags);
|
||||||
|
CHECK_VDP_WARNING(mixer, "Error when calling "
|
||||||
|
"vdp_output_surface_render_output_surface");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video->imgfmt != IMGFMT_VDPAU)
|
||||||
|
return -1;
|
||||||
|
|
||||||
struct mp_vdpau_mixer_frame *frame = mp_vdpau_mixed_frame_get(video);
|
struct mp_vdpau_mixer_frame *frame = mp_vdpau_mixed_frame_get(video);
|
||||||
struct mp_vdpau_mixer_frame fallback = {{0}};
|
struct mp_vdpau_mixer_frame fallback = {{0}};
|
||||||
|
Loading…
Reference in New Issue
Block a user