mirror of
https://github.com/mpv-player/mpv
synced 2025-03-11 08:37:59 +00: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;
|
||||
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)
|
||||
add_subs(mpctx, image);
|
||||
}
|
||||
|
@ -9,6 +9,15 @@ struct mp_hwdec_ctx {
|
||||
// API-specific, not needed by all backends.
|
||||
struct mp_vdpau_ctx *vdpau_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.
|
||||
|
@ -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.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->planes[1] && src->planes[1])
|
||||
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
|
||||
// are not needed anymore.
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -22,14 +22,42 @@
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/CGLIOSurface.h>
|
||||
|
||||
#include "video/decode/dec_video.h"
|
||||
#include "video/mp_image_pool.h"
|
||||
#include "gl_hwdec.h"
|
||||
|
||||
struct priv {
|
||||
CVPixelBufferRef pbuf;
|
||||
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)
|
||||
{
|
||||
if (hw->gl_texture_target != GL_TEXTURE_RECTANGLE) {
|
||||
@ -60,6 +88,9 @@ static int create(struct gl_hwdec *hw)
|
||||
if (!check_hwdec(hw))
|
||||
return -1;
|
||||
|
||||
hw->hwctx = &p->hwctx;
|
||||
hw->hwctx->download_image = download_image;
|
||||
|
||||
GL *gl = hw->gl;
|
||||
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 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)
|
||||
{
|
||||
struct priv *p = hw->priv;
|
||||
@ -136,7 +145,6 @@ static void destroy(struct gl_hwdec *hw)
|
||||
p->gl_texture = 0;
|
||||
}
|
||||
|
||||
|
||||
const struct gl_hwdec_driver gl_hwdec_vda = {
|
||||
.api_name = "vda",
|
||||
.imgfmt = IMGFMT_VDA,
|
||||
@ -144,6 +152,5 @@ const struct gl_hwdec_driver gl_hwdec_vda = {
|
||||
.reinit = reinit,
|
||||
.map_image = map_image,
|
||||
.unmap_image = unmap_image,
|
||||
.download_image = download_image,
|
||||
.destroy = destroy,
|
||||
};
|
||||
|
@ -1671,7 +1671,7 @@ static void uninit_video(struct gl_video *p)
|
||||
|
||||
fbotex_uninit(p, &p->indirect_fbo);
|
||||
fbotex_uninit(p, &p->scale_sep_fbo);
|
||||
|
||||
|
||||
// Invalidate image_params to ensure that gl_video_config() will call
|
||||
// init_video() on uninitialized gl_video.
|
||||
p->image_params = (struct mp_image_params){0};
|
||||
@ -2017,16 +2017,14 @@ struct mp_image *gl_video_download_image(struct gl_video *p)
|
||||
|
||||
struct video_image *vimg = &p->image;
|
||||
|
||||
if (!p->have_image || !gl->GetTexImage)
|
||||
if (!p->have_image)
|
||||
return NULL;
|
||||
|
||||
if (p->hwdec_active && p->hwdec->driver->download_image) {
|
||||
struct mp_image *dlimage =
|
||||
p->hwdec->driver->download_image(p->hwdec, vimg->hwimage);
|
||||
if (dlimage)
|
||||
mp_image_set_attributes(dlimage, &p->image_params);
|
||||
return dlimage;
|
||||
}
|
||||
if (p->hwdec_active)
|
||||
return mp_image_new_ref(vimg->hwimage);
|
||||
|
||||
if (!gl->GetTexImage)
|
||||
return 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];
|
||||
if (!hwimg)
|
||||
return NULL;
|
||||
struct mp_image *img = va_surface_download(hwimg, NULL);
|
||||
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;
|
||||
return mp_image_new_ref(hwimg);
|
||||
}
|
||||
|
||||
static void free_subpicture(struct priv *p, struct vaapi_osd_image *img)
|
||||
|
@ -80,7 +80,6 @@ struct vdpctx {
|
||||
VdpPresentationQueue flip_queue;
|
||||
|
||||
VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES];
|
||||
VdpOutputSurface screenshot_surface;
|
||||
int num_output_surfaces;
|
||||
VdpOutputSurface black_pixel;
|
||||
|
||||
@ -176,24 +175,16 @@ static int render_video_to_output_surface(struct vo *vo,
|
||||
"vdp_presentation_queue_block_until_surface_idle");
|
||||
|
||||
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;
|
||||
vdp_st = vdp->output_surface_render_output_surface(output_surface,
|
||||
NULL, vc->black_pixel,
|
||||
NULL, NULL, NULL,
|
||||
flags);
|
||||
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_opts opts = {0};
|
||||
if (frame)
|
||||
@ -344,12 +335,6 @@ static void free_video_specific(struct vo *vo)
|
||||
|
||||
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) {
|
||||
vdp_st = vdp->output_surface_destroy(vc->black_pixel);
|
||||
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;
|
||||
for (int i = 0; i < MAX_OUTPUT_SURFACES; i++)
|
||||
vc->output_surfaces[i] = VDP_INVALID_HANDLE;
|
||||
vc->screenshot_surface = VDP_INVALID_HANDLE;
|
||||
vc->vdp_device = VDP_INVALID_HANDLE;
|
||||
for (int i = 0; i < MAX_OSD_PARTS; 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct vdpctx *vc = vo->priv;
|
||||
@ -1092,10 +1052,12 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||
if (!status_ok(vo))
|
||||
return false;
|
||||
struct voctrl_screenshot_args *args = data;
|
||||
if (args->full_window)
|
||||
if (args->full_window) {
|
||||
args->out_image = get_window_screenshot(vo);
|
||||
else
|
||||
args->out_image = get_screenshot(vo);
|
||||
} else {
|
||||
args->out_image =
|
||||
vc->current_image ? mp_image_new_ref(vc->current_image) : NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case VOCTRL_GET_PREF_DEINT:
|
||||
|
@ -84,6 +84,13 @@ uint32_t va_fourcc_from_imgfmt(int imgfmt)
|
||||
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 {
|
||||
VAImageFormat *entries;
|
||||
int num;
|
||||
@ -125,6 +132,7 @@ struct mp_vaapi_ctx *va_initialize(VADisplay *display, struct mp_log *plog)
|
||||
.hwctx = {
|
||||
.priv = res,
|
||||
.vaapi_ctx = res,
|
||||
.download_image = ctx_download_image,
|
||||
},
|
||||
};
|
||||
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 tmp;
|
||||
if (va_image_map(p->ctx, image, &tmp)) {
|
||||
dst = pool ? mp_image_pool_get(pool, tmp.imgfmt, tmp.w, tmp.h)
|
||||
: mp_image_alloc(tmp.imgfmt, tmp.w, tmp.h);
|
||||
dst = mp_image_pool_get(pool, tmp.imgfmt, tmp.w, tmp.h);
|
||||
if (dst)
|
||||
mp_image_copy(dst, &tmp);
|
||||
va_image_unmap(p->ctx, image);
|
||||
}
|
||||
mp_image_copy_attributes(dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,76 @@
|
||||
#include "osdep/timer.h"
|
||||
|
||||
#include "video/out/x11_common.h"
|
||||
#include "video/img_format.h"
|
||||
#include "video/mp_image.h"
|
||||
#include "img_format.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)
|
||||
{
|
||||
@ -305,7 +373,9 @@ struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11
|
||||
.hwctx = {
|
||||
.priv = ctx,
|
||||
.vdpau_ctx = ctx,
|
||||
.download_image = download_image,
|
||||
},
|
||||
.getimg_surface = VDP_INVALID_HANDLE,
|
||||
};
|
||||
mpthread_mutex_init_recursive(&ctx->preempt_lock);
|
||||
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) {
|
||||
vdp_st = vdp->device_destroy(ctx->vdp_device);
|
||||
CHECK_VDP_WARNING(ctx, "Error when calling vdp_device_destroy");
|
||||
|
@ -12,14 +12,17 @@
|
||||
#include "common/msg.h"
|
||||
#include "hwdec.h"
|
||||
|
||||
#define CHECK_VDP_ERROR(ctx, message) \
|
||||
#define CHECK_VDP_ERROR_ST(ctx, message, statement) \
|
||||
do { \
|
||||
if (vdp_st != VDP_STATUS_OK) { \
|
||||
MP_ERR(ctx, "%s: %s\n", message, vdp->get_error_string(vdp_st)); \
|
||||
return -1; \
|
||||
statement \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_VDP_ERROR(ctx, message) \
|
||||
CHECK_VDP_ERROR_ST(ctx, message, return -1;)
|
||||
|
||||
#define CHECK_VDP_WARNING(ctx, message) \
|
||||
do { \
|
||||
if (vdp_st != VDP_STATUS_OK) \
|
||||
@ -71,6 +74,9 @@ struct mp_vdpau_ctx {
|
||||
bool in_use;
|
||||
int64_t age;
|
||||
} 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);
|
||||
|
@ -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(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(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;
|
||||
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 fallback = {{0}};
|
||||
|
Loading…
Reference in New Issue
Block a user