summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-01-22 17:47:14 +0100
committerwm4 <wm4@nowhere>2015-01-22 18:18:23 +0100
commit74581a61064f56b170e555fa72d9cdca161d2307 (patch)
tree532223eaa3644b01501d443ebca9011ee12af963
parente9ac3fc3a1505c4db1773a2a24d35ac41ab69887 (diff)
downloadmpv-74581a61064f56b170e555fa72d9cdca161d2307.tar.bz2
mpv-74581a61064f56b170e555fa72d9cdca161d2307.tar.xz
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.
-rw-r--r--player/screenshot.c10
-rw-r--r--video/hwdec.h9
-rw-r--r--video/mp_image.c1
-rw-r--r--video/out/gl_hwdec.h4
-rw-r--r--video/out/gl_hwdec_vda.c57
-rw-r--r--video/out/gl_video.c16
-rw-r--r--video/out/vo_vaapi.c9
-rw-r--r--video/out/vo_vdpau.c52
-rw-r--r--video/vaapi.c12
-rw-r--r--video/vdpau.c81
-rw-r--r--video/vdpau.h10
-rw-r--r--video/vdpau_functions.inc2
-rw-r--r--video/vdpau_mixer.c16
13 files changed, 182 insertions, 97 deletions
diff --git a/player/screenshot.c b/player/screenshot.c
index 4e22afc69d..7d1c743e40 100644
--- a/player/screenshot.c
+++ b/player/screenshot.c
@@ -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);
}
diff --git a/video/hwdec.h b/video/hwdec.h
index 149cd81bae..a7d2cf8c4b 100644
--- a/video/hwdec.h
+++ b/video/hwdec.h
@@ -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.
diff --git a/video/mp_image.c b/video/mp_image.c
index 95ed5ae08a..cf17429d89 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -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);
diff --git a/video/out/gl_hwdec.h b/video/out/gl_hwdec.h
index 8d2f563d5e..ffe685fa97 100644
--- a/video/out/gl_hwdec.h
+++ b/video/out/gl_hwdec.h
@@ -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);
};
diff --git a/video/out/gl_hwdec_vda.c b/video/out/gl_hwdec_vda.c
index 4264dff975..d90b3419ae 100644
--- a/video/out/gl_hwdec_vda.c
+++ b/video/out/gl_hwdec_vda.c
@@ -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,
};
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index e3eb4d1abf..1f32844c07 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -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);
diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c
index cf07787a48..06c7b3c9f4 100644
--- a/video/out/vo_vaapi.c
+++ b/video/out/vo_vaapi.c
@@ -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(&params); // ensure colorspace consistency
- mp_image_set_params(img, &params);
- return img;
+ return mp_image_new_ref(hwimg);
}
static void free_subpicture(struct priv *p, struct vaapi_osd_image *img)
diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c
index a022946c1b..e89cda6490 100644
--- a/video/out/vo_vdpau.c
+++ b/video/out/vo_vdpau.c
@@ -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:
diff --git a/video/vaapi.c b/video/vaapi.c
index 13e78f0f31..54d75e775a 100644
--- a/video/vaapi.c
+++ b/video/vaapi.c
@@ -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;
}
diff --git a/video/vdpau.c b/video/vdpau.c
index 3f7488470c..e1daf327af 100644
--- a/video/vdpau.c
+++ b/video/vdpau.c
@@ -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");
diff --git a/video/vdpau.h b/video/vdpau.h
index 0af00f098b..2304ecd0d6 100644
--- a/video/vdpau.h
+++ b/video/vdpau.h
@@ -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);
diff --git a/video/vdpau_functions.inc b/video/vdpau_functions.inc
index 5604420f69..001a0e9906 100644
--- a/video/vdpau_functions.inc
+++ b/video/vdpau_functions.inc
@@ -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)
diff --git a/video/vdpau_mixer.c b/video/vdpau_mixer.c
index d3a4a02457..3c8f3fb908 100644
--- a/video/vdpau_mixer.c
+++ b/video/vdpau_mixer.c
@@ -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}};